9

I have an array of n numbers, say [1,4,6,2,3]. The sorted array is [1,2,3,4,6], and the indexes of these numbers in the old array are 0, 3, 4, 1, and 2. What is the best way, given an array of n numbers, to find this array of indexes?

My idea is to run order statistics for each element. However, since I have to rewrite this function many times (in contest), I'm wondering if there's a short way to do this.

jscs
  • 63,694
  • 13
  • 151
  • 195
neutralino
  • 339
  • 1
  • 7
  • 10
  • 1
    Could you show an attempt you've made? – whereswalden Aug 28 '14 at 02:07
  • If you reverse the definition of the task, you get the same as here: https://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python – mathse Jun 12 '20 at 19:29
  • The example for this question is a bit ambiguous. There are two operations you could potentially wish to carry out. 1.) for each element in the original list, get that element's position in the sorted list. 2.) for each element in the sorted list, get that element's position in the original list. In your example, the sorted array indices `[0,3,4,1,2]` satisfy both tasks, but in general this is not the case. For instance, given input list `[1,6,4,2,3]`, the output of task 1 is `[0,4,3,1,2]` and the output for task 2 is `[0,3,4,2,1]`. – DerekG Apr 25 '21 at 16:11

5 Answers5

16
>>> a = [1,4,6,2,3]
>>> [b[0] for b in sorted(enumerate(a),key=lambda i:i[1])]
[0, 3, 4, 1, 2]

Explanation:

enumerate(a) returns an enumeration over tuples consisting of the indexes and values in the original list: [(0, 1), (1, 4), (2, 6), (3, 2), (4, 3)]

Then sorted with a key of lambda i:i[1] sorts based on the original values (item 1 of each tuple).

Finally, the list comprehension [b[0] for b in ...] returns the original indexes (item 0 of each tuple).

Mark Reed
  • 91,912
  • 16
  • 138
  • 175
user2085282
  • 1,077
  • 1
  • 8
  • 16
  • This will create an enumerated list, sort it based on the original key, then return the associated index. A very efficient solution w/ regards to speed and code length. – Andrew Johnson Aug 28 '14 at 02:17
  • Why thank you. I probably should've commented it, thanks for that, list comprehensions can be a bit hard to digest. – user2085282 Aug 28 '14 at 02:19
3

Using numpy arrays instead of lists may be beneficial if you are doing a lot of statistics on the data. If you choose to do so, this would work:

import numpy as np
a = np.array( [1,4,6,2,3] )
b = np.argsort( a )

argsort() can operate on lists as well, but I believe that in this case it simply copies the data into an array first.

Lukeclh
  • 231
  • 1
  • 5
1

Here is another way:

>>> sorted(xrange(len(a)), key=lambda ix: a[ix])
[0, 3, 4, 1, 2]

This approach sorts not the original list, but its indices (created with xrange), using the original list as the sort keys.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384
  • If you're generating the full list of indices anyway in order to sort it, why use `xrange` instead of `range`? – Mark Reed Aug 28 '14 at 02:47
  • @MarkReed: I believe that `sorted` will consume the `xrange` one element at a time. This means only one list will be generated (the sorted version); the list of unsorted indices will not be pre-generated and stored. – BrenBarn Aug 28 '14 at 02:49
0

This should do the trick:

from operator import itemgetter
indices = zip(*sorted(enumerate(my_list), key=itemgetter(1)))[0]
Joel Cornett
  • 24,192
  • 9
  • 66
  • 88
0

The long way instead of using list comprehension for beginner like me

a = [1,4,6,2,3]

b = enumerate(a)
c = sorted(b, key = lambda i:i[1])
d = []

for e in c:
    d.append(e[0])
    
print(d)
panda_cw
  • 1
  • 1