Sorting List Based on Values from Another List

Sorting list based on values from another list

Shortest Code

[x for _, x in sorted(zip(Y, X))]

Example:

X = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
Y = [ 0, 1, 1, 0, 1, 2, 2, 0, 1]

Z = [x for _,x in sorted(zip(Y,X))]
print(Z) # ["a", "d", "h", "b", "c", "e", "i", "f", "g"]

Generally Speaking

[x for _, x in sorted(zip(Y, X), key=lambda pair: pair[0])]

Explained:

  1. zip the two lists.
  2. create a new, sorted list based on the zip using sorted().
  3. using a list comprehension extract the first elements of each pair from the sorted, zipped list.

For more information on how to set\use the key parameter as well as the sorted function in general, take a look at this.



How to sort one list and re-sort another list keeping same relation python?

You could use this:

list1, list2 = zip(*sorted(zip(list1, list2)))

or this:

order = sorted(range(len(list1)), key=lambda i: list1[i])
list1 = [list1[i] for i in order]
list2 = [list2[i] for i in order]

The first one makes a new list that has matching pairs from list1 and list2, then sorts the pairs, which will mainly focus on the values that came from list1, and use the list2 value as a tiebreaker. Then zip(*new_list) is a standard Python trick for splitting the pairs back into separate lists. It combines all the pairs together to make a new list with two long rows, one with the first item from each pair and one with the second item. Then assigning that list to two variables splits it into two lists.

The second one creates indexes for the items in both lists, then sorts the indexes using the corresponding item from list1 as a key. Then it retrieved the items from each list using the new ordering.

Or this hybrid may be more readable:

sorted_pairs = sorted(zip(list1, list2))
list1 = [v1 for v1, v2 in sorted_pairs]
list2 = [v2 for v1, v2 in sorted_pairs]

Python 3.x -- sort one list based on another list and then return both lists sorted

Is it possible to merge the last two lines into one line?

Yes it is. ordered_candidates excludes the points from the result, since you only choose the candidates with [x for _, x in...]. This basically only selects the second item from each tuple. Additionally, ordered_points sorts only the points. They both also sort in reverse with reverse=True.

Seems like you can just modify ordered_candidates to include both items in the (point, candidate) pairs.

>>> points = [4,7,3,2,7]
>>> candidates = ['a', 'b', 'c', 'd', 'e']
>>> sorted(zip(points, candidates), reverse=True)
[(7, 'e'), (7, 'b'), (4, 'a'), (3, 'c'), (2, 'd')]

How to sort two lists (which reference each other) in the exact same way

One classic approach to this problem is to use the "decorate, sort, undecorate" idiom, which is especially simple using python's built-in zip function:

>>> list1 = [3,2,4,1, 1]
>>> list2 = ['three', 'two', 'four', 'one', 'one2']
>>> list1, list2 = zip(*sorted(zip(list1, list2)))
>>> list1
(1, 1, 2, 3, 4)
>>> list2
('one', 'one2', 'two', 'three', 'four')

These of course are no longer lists, but that's easily remedied, if it matters:

>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2))))
>>> list1
[1, 1, 2, 3, 4]
>>> list2
['one', 'one2', 'two', 'three', 'four']

It's worth noting that the above may sacrifice speed for terseness; the in-place version, which takes up 3 lines, is a tad faster on my machine for small lists:

>>> %timeit zip(*sorted(zip(list1, list2)))
100000 loops, best of 3: 3.3 us per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100000 loops, best of 3: 2.84 us per loop

On the other hand, for larger lists, the one-line version could be faster:

>>> %timeit zip(*sorted(zip(list1, list2)))
100 loops, best of 3: 8.09 ms per loop
>>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups)
100 loops, best of 3: 8.51 ms per loop

As Quantum7 points out, JSF's suggestion is a bit faster still, but it will probably only ever be a little bit faster, because Python uses the very same DSU idiom internally for all key-based sorts. It's just happening a little closer to the bare metal. (This shows just how well optimized the zip routines are!)

I think the zip-based approach is more flexible and is a little more readable, so I prefer it.


Note that when elements of list1 are equal, this approach will end up comparing elements of list2. If elements of list2 don't support comparison, or don't produce a boolean when compared (for example, if list2 is a list of NumPy arrays), this will fail, and if elements of list2 are very expensive to compare, it might be better to avoid comparison anyway.

In that case, you can sort indices as suggested in jfs's answer, or you can give the sort a key function that avoids comparing elements of list2:

result1, result2 = zip(*sorted(zip(list1, list2), key=lambda x: x[0]))

Also, the use of zip(*...) as a transpose fails when the input is empty. If your inputs might be empty, you will have to handle that case separately.

Sorting a list based on values from another list and excluding elements in list from the sort?

You can use np.argsort on the portion you want:

order = np.r_[0,np.argsort(A[1:-1]) + 1, len(A)-1]
a_new = np.array(A)[order]
b_new = np.array(B)[order]
c_new = np.array(C)[order]

Output:

[50000 -4000 -3000  8000 51000]
['Start' 'Cost1' 'Cost2' 'Profit1' 'End']
['50K' '-4k' '-3k' '8k' '51k']

Kotlin: Sort list based on another list (different objects)

The easiest approach would be to first create a mapping of the list you want to sort by. It should associate the id to the actual object.

Then you iterate the list you want to sort by and map it's values to the object you retrieved from the mapping you just created.

Here a minimal example:

// both can have more properties of course
data class Foo(val id: Int)
data class Bar(val id: Int)

val fooList = listOf(Foo(4), Foo(2), Foo(1), Foo(3))
val barList = listOf(Bar(1), Bar(2), Bar(3), Bar(4))

val idValueMap = barList.associateBy { it.id }

val sortedByOtherList = fooList.map { idValueMap[it.id] }

println(sortedByOtherList)

Result:

[Bar(id=4), Bar(id=2), Bar(id=1), Bar(id=3)]

Python, sort a list by another list

You can try passing a lambda function to the key parameter of the sorted() built-in function:

a = ['c', 'd', 'B', 'a', 'e']
b = ['a001', 'B002', 'c003', 'd004', 'e005']
c = sorted(b, key = lambda x: a.index(x[0])) # ['c003', 'd004', 'b002', 'a001', 'e005']

Sorting a list based off of values in another list

Try this way:

Step 1: create a dictionary be getting key from the pdf's file name

In this,step I extract the digits only on the last string joined with .pdf

d={}
for p in pdfs:
key = re.findall(r'\d+',p.split()[-1].rstrip('.pdf'))[0]
d[key] = p

Step 2: creat a new list to store the file name according to the your invoice_ordering_list

new_pdf=[]
for k in invoice_ordering_list:
new_pdf.append(d[k])

Python sort list based on values in another list with matching pattern

That should work for you

sorted_L1 = sorted(L1, key=lambda x: 12 * int(x[2:].split('_')[0]) + L2.index(x[:3]))


Related Topics



Leave a reply



Submit