Given a list
[ ['a','b'], ['x','y'], ['a','y'], ['x', 'b'] ]
How can I sort it in a way that the first element is sorted decreasingly, but the second element is sorted increasingly when the first element equal? The strings can be arbitrarily long in this list.
The sorted list should be
[ ['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y'] ]
I'm thinking about using one single call of sorted
, but making up a key to reflect this seems not working.
You can sort it twice (Python uses a stable sort that performs well on already-sorted portions):
>>> l = [ ['a','b'], ['x','y'], ['a','y'], ['x', 'b'] ]
>>> sorted(sorted(l, key=lambda x: x[1]), key=lambda x: x[0], reverse=True)
[['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y']]
Or you can use ord()
to get an integer and negate it:
>>> l = [ ['a','b'], ['x','y'], ['a','y'], ['x', 'b'] ]
>>> sorted(l, key=lambda x: (-ord(x[0]), x[1]))
[['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y']]
Well,
The way I thought at first time was:
l.sort(key=lambda e: (255 - ord(e[0]), e[1]))
But this way the element must be a tuple (I understood that's the case), and de first element of each tuple must be a string/character.
Better solutions can evolve from here.
In Python 2 you can do this:
>>> l = [ ['a','b'], ['x','y'], ['a','y'], ['x', 'b'] ]
>>>
>>> sorted(l, lambda (a, b), (c, d): cmp(c, a) or cmp(b, d))
[['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y']]
The same thing in Python 3 is possible, but ugly:
>>> import functools
>>> sorted(l, key=functools.cmp_to_key(lambda a, b: (a[0] < b[0]) - (a[0] > b[0]) or (a[1] > b[1]) - (a[1] < b[1])))
[['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y']]
Or with a helper:
>>> def cmp(a, b):
return (a > b) - (a < b)
>>> sorted(l, key=functools.cmp_to_key(lambda a, b: cmp(b[0], a[0]) or cmp(a[1], b[1])))
[['x', 'b'], ['x', 'y'], ['a', 'b'], ['a', 'y']]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.