How to sort a list with two keys but one in reverse order?
I was wondering what would be a Pythonic way of sorting a list of tuples by two keys whereby sorting with one (and only one) key would be in a reverse order and sorting with the the other would be case insensitive. More specifically, I have a list containing tuples like:
myList = [(ele1A, ele2A),(ele1B, ele2B),(ele1C, ele2C)]
I can use the following code to sort it with two keys:
sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1]))
To sort in reverse order I can use
sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1]), reverse = True)
But this would sort in a reverse order with two keys.
Two keys will be used when we need to sort a list with two constraints one in ascending order and other in descending in the same list or any
In your example sortedList = sorted(myList, key = lambda y: (y[0].lower(), y[1]))
can sort entire list only in one order
you can try these and check whats happening
sortedList = sorted(myList, key = lambda y: (y[0].lower(), -y[1]))
sortedList = sorted(myList, key = lambda y: (-y[0].lower(), y[1]))
sortedList = sorted(myList, key = lambda y: (-y[0].lower(), -y[1]))
hope you will understand after this ;)
You could create a reversor class and use it to decorate the key in question. This class could be used to reverse any field that is comparable.
class reversor:
def __init__(self, obj):
self.obj = obj
def __eq__(self, other):
return other.obj == self.obj
def __lt__(self, other):
return other.obj < self.obj
Use it like so:
sortedList = sorted(myList, key=lambda(y): (y[0].lower(), reversor(y[1])))
Sometimes there is little alternative but to use a comparator function. There was a cmp
argument to sorted
from its introduction to 2.4, but it was removed from Python 3 in favour of the more efficient key
function. In 3.2, cmp_to_key
was added to functools
; it creates keys from the original objects by wrapping them in an object whose comparison function is based on the cmp
function. (You can see a simple definition of cmp_to_key
at the end of the Sorting How-To
In your case, since lower-casing is relatively expensive, you might want to do a combination:
class case_insensitive_and_2nd_reversed:
def __init__(self, obj, *args):
self.first = obj[0].lower()
self.second = obj[1]
def __lt__(self, other):
return self.first < other.first or self.first == other.first and other.second < self.second
def __gt__(self, other):
return self.first > other.first or self.first == other.first and other.second > self.second
def __le__(self, other):
return self.first < other.first or self.first == other.first and other.second <= self.second
def __ge__(self, other):
return self.first > other.first or self.first == other.first and other.second >= self.second
def __eq__(self, other):
return self.first == other.first and self.second == other.second
def __ne__(self, other):
return self.first != other.first and self.second != other.second
sortedList = sorted(myList, key = case_insensitive_and_2nd_reversed)