1

I want to create a new list with the elements of a list, but sorted according to the values of another list.

Example:

list = [12, 17, 26, 28, 29, 33, 34, 37, 41, 43, 45, 64, 70]

index_list = [9, 10, 0, 1, 2, 6, 8, 7, 3, 5, 4, 11, 12]

the result should be:

final_list = [26, 28, 29, 41, 45, 43, 33, 37, 34, 12, 17, 64, 70]

I tried to do it with the insert method:

final_list = []
for i in range(len(list)):
   final_list.insert(index_list[i], list[i])
print(final_list)

but the output is not correct:

[26, 28, 29, 41, 45, 12, 43, 17, 33, 34, 37, 64, 70]
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Jisus
  • 19
  • 2
  • 2
    Does this answer your question? [Sorting list based on values from another list](https://stackoverflow.com/questions/6618515/sorting-list-based-on-values-from-another-list) – mkrieger1 May 05 '22 at 19:19
  • Interestingly, if instead of `index_list` you had the inverse permutation, and if the first list was a numpy array, then you could use the second list as an "index" for the first list `l1[l2]` and you'd get your result directly, in linear-time and very convenient notation. – Stef May 05 '22 at 19:59

3 Answers3

3

There's really no need to sort anything:

alist = [12, 17, 26, 28, 29, 33, 34, 37, 41, 43, 45, 64, 70]
index_list = [9, 10, 0, 1, 2, 6, 8, 7, 3, 5, 4, 11, 12]

res = [0] * len(index_list)
for i, j in enumerate(index_list):
    res[j] = alist[i]

print(res)

prints

[26, 28, 29, 41, 45, 43, 33, 37, 34, 12, 17, 64, 70]
 
Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
1

zip the two lists together (with the indices as the first part of each tuple) and sort the result:

>>> a_list = [12, 17, 26, 28, 29, 33, 34, 37, 41, 43, 45, 64, 70]
>>> index_list = [9, 10, 0, 1, 2, 6, 8, 7, 3, 5, 4, 11, 12]
>>> sorted(zip(index_list, a_list))
[(0, 26), (1, 28), (2, 29), (3, 41), (4, 45), (5, 43), (6, 33), (7, 37), (8, 34), (9, 12), (10, 17), (11, 64), (12, 70)]

Then just pull out the elements corresponding to the original a_list:

>>> [i[1] for i in sorted(zip(index_list, a_list))]
[26, 28, 29, 41, 45, 43, 33, 37, 34, 12, 17, 64, 70]
Samwise
  • 68,105
  • 3
  • 30
  • 44
0

Similar to Antony's, but more direct (no need for extra indexes by enumerate):

alist = [12, 17, 26, 28, 29, 33, 34, 37, 41, 43, 45, 64, 70]
index_list = [9, 10, 0, 1, 2, 6, 8, 7, 3, 5, 4, 11, 12]

res = [None] * len(alist)
for i, res[i] in zip(index_list, alist):
    pass

print(res)

Output (Try it online!):

[26, 28, 29, 41, 45, 43, 33, 37, 34, 12, 17, 64, 70]
Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
  • Yes, this is sleek! +1 Yet I'd probably refrain from such code in production: `pass` inside a `for` loop is somewhat puzzling at first glance. – Antony Hatchkins May 05 '22 at 20:21
  • @AntonyHatchkins Hmm, but what am I supposed to do inside the loop? The work has already been done, there's nothing left to do. I need to write *something* so that it's syntactically valid, and I think `pass` is the proper thing for that. – Kelly Bundy May 05 '22 at 20:27
  • Syntactically it is fine. It is just looks somewhat counter-intuitive for an unaware reader. In my opinion the code should be self-documenting. This one is rather not. It is more haskellish than pythonic :) – Antony Hatchkins May 06 '22 at 04:08
  • As for 'what am I supposed to do' – `for i, v in zip(index_list, alist): res[i]=v` would look more pythonic to me. – Antony Hatchkins May 06 '22 at 04:10
  • @AntonyHatchkins I don't know Haskell, so I can't tell :-). I don't like the detour through an extra variable like `v`. Then I have to think of a name for it, Python needs to additionally store and load it, I have to think through that additional storing and loading, and I have an extra variable floating around after the loop. – Kelly Bundy May 06 '22 at 13:57
  • I recommend you have a look at Haskell ;) You're misusing python here. If you're after speed, c++/rust/go is a better choice. If you're after elegance, it is haskell. Python is about readability. – Antony Hatchkins May 06 '22 at 15:22
  • @AntonyHatchkins I'm certainly interested in Haskell, already have Hutton's book, but in another city :-(. How am I "misusing" Python here? I don't think I am. And the only real downside I see is that apparently some people hate this so much that I often get downvotes for this (in this case despite me also avoiding the iterating-by-extra-indexes-from-enumerate, and that alone already makes this answer **not** "not useful", in my opinion). – Kelly Bundy May 06 '22 at 15:31
  • I've upvoted your answer, not downvoted it :) I don't hate it and I find it useful. My only point that in my opinion while this code is perfectly suitable for a hobby project, it is not desirable for production. Anyway I feel it's a bit too much of a discussion for a one-liner. And I think we've understood each other. Thank you for your answer, I hope the OP also upvotes it. I'd also recommend not to take downvotes to your heart. My most upvoted answer with 1300 upvotes has 6 downvotes, too. Who are those 6 people? Why did they do it? I don't really care. – Antony Hatchkins May 06 '22 at 18:57
  • @AntonyHatchkins Yeah yeah, I know it wasn't you, from your first comment and the upvote that came with it. Six downs among 1300 ups are a totally different story. Most people can't even see them. But answers with negative net votes aren't looked at much, so it's wasted effort. That does bother me. – Kelly Bundy May 06 '22 at 22:39