Reputation: 1287
Sorry for not being able to come out with a good title.
I have a list:
some_list = [[X, '4x01'], [X, '3x02'], [X, '4x02'], [X, '3x01']]
where X
is something I don't care.
I want to sort the second element in the list with the following priorities:
The final output should be:
some_list = [[X, '4x01'], [X, '4x02'], [X, '3x01'], [X, '3x02']]
Note: The solution that gives the incorrect answer is:
output = sorted(some_list, key=lambda lis: lis[3], reverse=True)
Upvotes: 2
Views: 2607
Reputation: 500595
In this case you could use a composite key as @Amber did. However, that approach doesn't always work: for example, it would fail if both components were two characters long (since the -ord(x[1][0])
trick would no longer work).
Here is a more general solution:
In [15]: X = None
In [16]: some_list = [[X, '4x01'], [X, '3x02'], [X, '4x02'], [X, '3x01']]
In [17]: l = sorted(some_list, key=lambda (x,y):y[-2:])
In [18]: l = sorted(l, key=lambda (x,y):y[:1], reverse=True)
In [19]: l
Out[19]: [[None, '4x01'], [None, '4x02'], [None, '3x01'], [None, '3x02']]
It sorts the list one criterion at a time, and makes use of the fact that Python's sort is stable.
An even more general approach is to provide a comparator:
def f((x1,y1), (x2,y2)):
c = cmp(y1[:1], y2[:1])
if c != 0: return -c
return cmp(y1[-2:], y2[-2:])
This can be used as follows:
In [39]: sorted(some_list, cmp=f)
Out[39]: [[None, '4x01'], [None, '4x02'], [None, '3x01'], [None, '3x02']]
Upvotes: 1
Reputation: 526923
output = sorted(some_list, key=lambda x: (-ord(x[1][0]), x[1][-2:]))
Example run (defining X as None
just so I can copy-paste your list definition):
>>> X = None
>>> some_list = [[X, '4x01'], [X, '3x02'], [X, '4x02'], [X, '3x01']]
>>> output = sorted(some_list, key=lambda x: (-ord(x[1][0]), x[1][-2:]))
>>> output
[[None, '4x01'], [None, '4x02'], [None, '3x01'], [None, '3x02']]
Upvotes: 6