fmonegaglia
fmonegaglia

Reputation: 2819

python sorting two lists

I am trying to sort two lists together:

list1 = [1, 2, 5, 4, 4, 3, 6]
list2 = [3, 2, 1, 2, 1, 7, 8]

list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2))))

Anyway, doing this gives me on output

list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 1, 2, 1, 8]

while I would want to keep the initial order for equal number 4 in the first list: what I want is

list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 2, 1, 1, 8]

What do I have to do? I wouldn't want to use loop for bubble-sorting. Any help appreciated.

Upvotes: 28

Views: 29833

Answers (3)

Mark Amery
Mark Amery

Reputation: 155176

The trick here is that when Python does tuple comparisons, it compares the elements in order from left to right (for example, (4, 1) < (4, 2), which is the reason that you don't get the ordering you want in your particular case). That means you need to pass in a key argument to the sorted function that tells it to only use the first element of the pair tuple as its sort expression, rather than the entire tuple.

This is guaranteed to retain the ordering you want because:

sorts are guaranteed to be stable. That means that when multiple records have the same key, their original order is preserved.

(source)

>>> list1 = [1, 2, 5, 4, 4, 3, 6]
>>> list2 = [3, 2, 1, 2, 1, 7, 8]
>>> 
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0])))
>>> 
>>> print list1
[1, 2, 3, 4, 4, 5, 6]
>>> print list2
[3, 2, 7, 2, 1, 1, 8]

Upvotes: 9

interjay
interjay

Reputation: 110202

Use a key parameter for your sort that only compares the first element of the pair. Since Python's sort is stable, this guarantees that the order of the second elements will remain the same when the first elements are equal.

>>> from operator import itemgetter
>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=itemgetter(0)))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]

Which is equivalent to:

>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0]))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]

Upvotes: 35

ovgolovin
ovgolovin

Reputation: 13430

In you code the sorting is performed basing on the first and the second elements of the tuples, so the resulting second list elements are in the sorted order for the same elements of the first list.

To avoid sorting based on the second list, just specify that only the elements from the first list should be used in the comparison of the tuples:

>>> from operator import itemgetter
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2),key=itemgetter(0))))
>>> list1, list2
([1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8])

itemgetter(0) takes the first element from each tuple, which belongs to the first list.

Upvotes: 0

Related Questions