# [Solved] sort Python list with two keys but only 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.

Any hints greatly appreciated.

## Solution #1:

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

`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 ðŸ˜‰

## Solution #2:

One way could be to 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]))
``````

## Solution #3:

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 __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)
``````

# Method 1

A simple solution, but might not be the most efficient is to sort twice: the first time using the second element, the second using the first element:

``````sortedList = sorted(sorted(myList, key=lambda (a,b):b, reverse=True), key=lambda(a,b):a)
``````

Or break down:

``````tempList = sorted(myList, key=lambda (a,b):b, reverse=True)
sortedList = sorted(tempList, key=lambda(a,b):a))
``````

# Method 2

If your elements are numbers, you can cheat a little:

``````sorted(myList, key=lambda(a,b):(a,1.0/b))
``````

# Method 3

Another approach is to swap the elements when comparing the elements:

``````def compare_func(x, y):
tup1 = (x[0], y[1])
tup2 = (x[1], y[0])
if tup1 == tup2:
return 0
elif tup1 > tup2:
return 1
else:
return -1

sortedList = sorted(myList, cmp=compare_func)
``````

Or, using lambda to avoid writing function:

``````sortedList = sorted(
myList,
cmd=lambda (a1, b1), (a2, b2): 0 if (a1, b2) == (a2, b1) else 1 if (a1, b2) > (a2, b1) else -1
)
``````

I recommend against this approach as it is messy and the `cmd` keyword is not available in Python 3

## Solution #5:

maybe elegant but not efficient way:

``````reverse_key = functools.cmp_to_key(lambda a, b: (a < b) - (a > b))
sortedList = sorted(myList, key = lambda y: (reverse_key(y[0].lower()), y[1]))
``````

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .