Simpler way of sorting list of lists indexed by one list in Python

I want to sort a list of two lists, where the elements in the two lists are pairs.

I want to sort the lists by the second element in these pairs.

For example if I have

a_list = [[51132, 55274, 58132], [190, 140, 180]]

and want

sorted_list = [[55274, 58132, 51132], [140, 180, 190]]

Is there a simpler way than the following in Python2.7?

from operator import itemgetter
sorted_list = map(list, zip(*sorted(map(list,zip(*a_list)), key=itemgetter(1))))

Best regards, Øystein

Upvotes: 3

Views: 114

Answers (2)

tobias_k
tobias_k

Reputation: 82899

I am a bit reluctant to post this as an answer, but why not, actually?

No, there is no simpler way to achieve your sort in Python -- except that you can drop that inner map:

>>> map(list, zip(*sorted(zip(*a_list), key=itemgetter(1))))
[[55274, 58132, 51132], [140, 180, 190]]

It may seem a bit convoluted at first (though not as much as with that additional map), but actually it's totally clear: You zip the list, sort by the second element, and zip it back. Everyone who knows Python should understand what the code does.

If you want to make it even clearer, either add a line comment describing what the sort does, or wrap it inside a function with a descriptive name and the same or a more extensive comment.

Upvotes: 2

aknuds1
aknuds1

Reputation: 67987

What you want according to my understanding is to sort each pair depending on the second element of the pair; that is to say, the ordering of the second element (of the pair) is to determine the ordering of the first element. The following code uses the corresponding position of the second element as the sorting key:

EDIT: I have made a revision that should solve the problem with duplicate elements, thanks for pointing that out:

class _Value:
    def __init__(self, pos, val):
        self.pos, self.val = pos, val

    def __lt__(self, other):
        return self.val < other.val


a_list = [[51132, 55274, 58132], [190, 140, 180]]
a_list = [[_Value(i, x) for i, x in enumerate(l)] for l in a_list]

sorted_list = [sorted(l, key=lambda x: a_list[1][x.pos]) for l in a_list]
sorted_list = [[x.val for x in l] for l in sorted_list]
assert sorted_list == [[55274, 58132, 51132], [140, 180, 190]]

Upvotes: 1

Related Questions