3

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

7
  • 1
    Please make clearer how you want the lists to be sorted. Commented Jun 27, 2014 at 8:28
  • 1
    what is pattern in your sorting ? Commented Jun 27, 2014 at 8:30
  • so....ummmm, sort the second list, and put the positions of the elements in the first one to mirror the shifts in position in the second list? Commented Jun 27, 2014 at 8:31
  • 4
    I think you can drop the inner map, apart from that it looks okay to me. Commented Jun 27, 2014 at 8:33
  • 1
    The only solution i could come up with looks exactly the same as yours :zip(*sorted(zip(*a_list), key=lambda x : x[1])) . The question is, why work with 2 lists and not a list of tuples if the items have a relation with each other ? Commented Jun 27, 2014 at 8:37

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

It might help to give each of the three phases its own line, so you can give the intermediate results meaningful names or comment each phase separately.
1

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]]

3 Comments

Thx, this answers my questions. But I'm not sure it's that much simpler though :)
The use of index causes quadratic performance degradation on large inputs and incorrect sort results when the input contains duplicates.
Better. It's still more complicated than necessary, though. I'm not sure why you bothered with the _Value class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.