Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a list of strings in reverse order without using reverse=True parameter?

I want to sort a list of strings in reverse order, e.g.:

my_list = ['aaa', 'bbb', 'ccc']

expected result:

['ccc', 'bbb', 'aaa']

I don't want to use sorted(my_list, reverse=True), because in more complex case when filtering by two values it would not work. For example:

my_list2 = [('aaa', 'bbb'), ('aaa', 'ccc'), ('bbb', 'aaa'), ('bbb', 'ccc')]

expected result would be:

[('bbb', 'aaa'), ('bbb', 'ccc'), ('aaa', 'bbb'), ('aaa', 'ccc')]

sorted(my_list2, reverse=True) returns:

[('bbb', 'ccc'), ('bbb', 'aaa'), ('aaa', 'ccc'), ('aaa', 'bbb')]

It is simple with numbers, you can negate the value:

>>> my_list3 = [(1, 2), (1, 3), (2, 1), (2, 3)]
>>> sorted(my_list3, key=lambda x: (-x[0], x[1]))
... [(2, 1), (2, 3), (1, 2), (1, 3)]

But how to do it with strings?

like image 979
niekas Avatar asked Apr 26 '19 11:04

niekas


People also ask

How do you sort a list in reverse order?

sort() method. This method requires two parameters i.e. the list to be sorted and the Collections. reverseOrder() that reverses the order of an element collection using a Comparator. The ClassCastException is thrown by the Collections.

How do you reverse sort a string in Python?

Method #1 : join() + sorted() + reverse key: The combination of above functions can potentially solve this particular problem. This task is performed in 2 steps in which the first step we get the reverse sorted list of characters and then we join the result to get the resultant sorted string.

How do I reverse a string list?

To reverse a string with the list reverse() method, first, the string needs to be converted to a list using the list constructor. Then the list items are reversed in place with the reverse() method, and finally, the list items are joined into a string using the join() method.

How do you sort numbers in reverse order in Python?

Summary. Use the Python List sort() method to sort a list in place. The sort() method sorts the string elements in alphabetical order and sorts the numeric elements from smallest to largest. Use the sort(reverse=True) to reverse the default sort order.


1 Answers

You'll have to sort twice. Python's sort algorithm is stable, which means that elements that are equal keep their relative order. Use this to first sort on the second element (sorting in ascending order), then sort that output again, on only the first element and in reverse order:

sorted(sorted(my_list2, key=lambda t: t[1]), key=lambda t: t[0], reverse=True)

Using operator.itemgetter() instead of lambdas can make this little bit faster (avoiding stepping back in to the Python interpreter for each element):

from operator import itemgetter

sorted(sorted(my_list2, key=itemgetter(1)), key=itemgetter(0), reverse=True)

Demo:

>>> from operator import itemgetter
>>> my_list2 = [('aaa', 'bbb'), ('aaa', 'ccc'), ('bbb', 'aaa'), ('bbb', 'ccc')]
>>> sorted(sorted(my_list2, key=lambda t: t[1]), key=lambda t: t[0], reverse=True)
[('bbb', 'aaa'), ('bbb', 'ccc'), ('aaa', 'bbb'), ('aaa', 'ccc')]
>>> sorted(sorted(my_list2, key=itemgetter(1)), key=itemgetter(0), reverse=True)
[('bbb', 'aaa'), ('bbb', 'ccc'), ('aaa', 'bbb'), ('aaa', 'ccc')]

The general rule is to sort from the innermost element to the outermost element. So for an arbitrary-element-count sort, with a key and a reverse boolean each, you can use the functools.reduce() function to apply these:

from functools import reduce
from operator import itemgetter

def sort_multiple(sequence, *sort_order):
    """Sort a sequence by multiple criteria.

    Accepts a sequence and 0 or more (key, reverse) tuples, where
    the key is a callable used to extract the value to sort on
    from the input sequence, and reverse is a boolean dictating if
    this value is sorted in ascending or descending order.

    """
    return reduce(
        lambda s, order: sorted(s, key=order[0], reverse=order[1]),
        reversed(sort_order),
        sequence
    )

sort_multiple(my_list2, (itemgetter(0), True), (itemgetter(1), False))
like image 52
Martijn Pieters Avatar answered Nov 15 '22 20:11

Martijn Pieters