Malgi
Malgi

Reputation: 730

How to sort a list of tuples based on the keys in a list?

I want to sort a list of tuples based on a number of keys. For example, I have this list of tuples:

list_t = [(1, 3, 5, 6, 9, 10), (1, 2, 3, 4, 5, 61), (1, 2, 3, 0, 9, 81), (1, 2, 6, 7, 9, 54), (1, 3, 5, 6, 12, 43)]

One time I want to sort it by the first, second, third, and fifth element of the tuples:

keys = [0, 1, 2, 4]
list_t_sorted = [(1, 2, 3, 4, 5, 61), (1, 2, 3, 0, 9, 81), (1, 2, 6, 7, 9, 54), (1, 3, 5, 6, 9, 10), (1, 3, 5, 6, 12, 43)]

And another time I need to sort it just by the third element of the tuples:

keys = [2]
list_t_sorted = [(1, 2, 3, 4, 5, 61), (1, 2, 3, 0, 9, 81), (1, 3, 5, 6, 9, 10), (1, 3, 5, 6, 12, 43), (1, 2, 6, 7, 9, 54)]

So far I tried this code but it does not return the expected results:

def sort_list(keys, list_t):
    return sorted(list_t, key=lambda l: (l[x] for x in keys))

For example, for keys = [0, 1, 2, 4] it returns [(1, 3, 5, 6, 9, 10), (1, 2, 3, 4, 5, 61), (1, 3, 5, 6, 12, 43), (1, 2, 6, 7, 9, 54), (1, 2, 3, 0, 9, 81)] which is not sorted based on the keys.

Can anybody help me? Thanks!

Upvotes: 2

Views: 187

Answers (2)

R Nar
R Nar

Reputation: 5515

michael_j_ward's answer is a much cleaner solution to your question, but if you want to know what went wrong with your original idea:

You are attempting to sort generator objects, which I am guessing has a different way of equating. A way to show this is by showing what you are actually attempting to sort with a for loop:

>>> def sort_list(keys, list_t):
...     for l in list_t:
...             print (l[x] for x in keys)
...     return sorted(list_t, key = lambda l: (l[x] for x in keys))
...
>>> sort_list(keys, list_t)
<generator object <genexpr> at 0x105bc1af0>
<generator object <genexpr> at 0x105bc1af0>
<generator object <genexpr> at 0x105bc1af0>
<generator object <genexpr> at 0x105bc1af0>
<generator object <genexpr> at 0x105bc1af0>
[(1, 3, 5, 6, 12, 43), (1, 2, 6, 7, 9, 54), (1, 2, 3, 0, 9, 81), (1, 2, 3, 4, 5, 61), (1, 3, 5, 6, 9, 10)]

This is obviously not your intended output, and it has to do with how those generators are being compared. If you want to do it with your original idea (without itemgetter), explicitly create tuples instead of generators:

>>> def sort_list(keys, list_t):
...     return sorted(list_t, key = lambda l: tuple(l[x] for x in keys))
...
>>> sort_list(keys, list_t)
[(1, 2, 3, 4, 5, 61), (1, 2, 3, 0, 9, 81), (1, 2, 6, 7, 9, 54), (1, 3, 5, 6, 9, 10), (1, 3, 5, 6, 12, 43)]

Upvotes: 2

michael_j_ward
michael_j_ward

Reputation: 4559

Here you go. You can read more about operator.itemgetter here in the docs.

import operator
list_t = [(1, 3, 5, 6, 9, 10), (1, 2, 3, 4, 5, 61), (1, 2, 3, 0, 9, 81), (1, 2, 6, 7, 9, 54), (1, 3, 5, 6, 12, 43)]
keys = [0, 1, 2, 4]
sorted(list_t, key=operator.itemgetter(*keys))

Outputs:

[(1, 2, 3, 4, 5, 61),
 (1, 2, 3, 0, 9, 81),
 (1, 2, 6, 7, 9, 54),
 (1, 3, 5, 6, 9, 10),
 (1, 3, 5, 6, 12, 43)]

Upvotes: 6

Related Questions