Sorting on multiple values, some ascending, some descending

Peter Otten __peter__ at web.de
Wed Jan 3 15:16:40 EST 2007


Raymond Hettinger wrote:

> dwelden wrote:
>> I have successfully used the sort lambda construct described in
>> http://mail.python.org/pipermail/python-list/2006-April/377443.html.
>> However, how do I take it one step further such that some values can be
>> sorted ascending and others descending? Easy enough if the sort values
>> are numeric (just negate the value), but what about text?
>>
>> Is the only option to define an external sorting function to loop
>> through the list and perform the comparisons one value at a time?
> 
> The simplest way is to take advantage of sort-stability and do
> successive sorts.  For example, to sort by a primary key ascending and
> a secondary key decending:
> 
>    L.sort(key=lambda r: r.secondary, reverse=True)
>    L.sort(key=lambda r: r.primary)
> 
> A less general technique is to transform fields in a way that reverses
> their comparison order:
> 
>   L.sort(key=lambda r: (-r.age, r.height))    # sorts descending age
> and ascending height

You can get generality if you are willing to pay the performance penalty:

>>> items
[(3, 1), (2, 2), (1, 1), (1, 3), (2, 1), (2, 3), (1, 2)]
>>> class Reverse:
...     def __cmp__(self, other):
...             return -cmp(self.value, other.value)
...     def __init__(self, value):
...             self.value = value
...
>>> items.sort(key=lambda (x, y): (x, Reverse(y)))
>>> items
[(1, 3), (1, 2), (1, 1), (2, 3), (2, 2), (2, 1), (3, 1)]

Peter



More information about the Python-list mailing list