Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort List in Python by two other lists

My question is very similar to these two links 1 and 2:

I have three different lists. I want to sort List1 based on List2 (in ascending order). However, I have repeats in List2. I then want to sort these repeats by List3 (in descending order). Confusing enough?

What I have:

List1 = ['a', 'b', 'c', 'd', 'e']
List2 = [4, 2, 3, 2, 4]
List3 = [0.1, 0.8, 0.3, 0.6, 0.4]

What I want:

new_List1 = ['b', 'd', 'c', 'e', 'a']

'b' comes before 'd' since 0.8 > 0.6. 'e' comes before 'a' since 0.4 > 0.1.

like image 897
mcfly Avatar asked Dec 19 '12 17:12

mcfly


People also ask

How do you sort two lists together in Python?

Approach : Zip the two lists. Create a new, sorted list based on the zip using sorted(). Using a list comprehension extract the first elements of each pair from the sorted, zipped list.

How do you sort one list by another list in Python?

Use the zip() and sorted() Functions to Sort the List Based on Another List in Python. In this method, we will use the zip() function to create a third object by combining the two given lists, the first which has to be sorted and the second on which the sorting depends.


1 Answers

I think you should be able to do this by:

paired_sorted = sorted(zip(List2,List3,List1),key = lambda x: (x[0],-x[1]))
l2,l3,l1 = zip(*paired_sorted)

In action:

>>> List1 = ['a', 'b', 'c', 'd', 'e']
>>> List2 = [4, 2, 3, 2, 4]
>>> List3 = [0.1, 0.8, 0.3, 0.6, 0.4]
>>> paired_sorted = sorted(zip(List2,List3,List1),key = lambda x: (x[0],-x[1]))
>>> l2,l3,l1 = zip(*paired_sorted)
>>> print l1
('b', 'd', 'c', 'e', 'a')

Here's how it works. First we match corresponding elements from your lists using zip. We then sort those elements based on the items from List2 first and (negated) List3 second. Then we just need to pull off the List1 elements again using zip and argument unpacking -- Although you could do it easily with a list-comprehension if you wanted to make sure you had a list at the end of the day instead of a tuple.

This gets a little tougher if you can't easily negate the values in List3 -- e.g. if they're strings. You need to do the sorting in 2 passes:

paired = zip(List2,List3,List1)
rev_sorted = sorted(paired,reverse=True,key=lambda x: x[1])  #"minor" sort first
paired_sorted = sorted(rev_sorted,key=lambda x:x[0])         #"major" sort last
l2,l3,l1 = zip(*paired_sorted)

(you could use operator.itemgetter(1) in place of lambda x:x[1] in the above if you prefer). This works because python sorting is "stable". It doesn't re-order "equal" elements.

like image 146
mgilson Avatar answered Oct 04 '22 06:10

mgilson