简体   繁体   中英

What is the pythonic way to sort a list with multiple attributes, such that the first is sorted reversely but the second is not?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM