Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to return index of a sorted list? [duplicate]

Tags:

python

People also ask

How do I find the index of a duplicate element in a list?

Method #1 : Using loop + set() In this, we just insert all the elements in set and then compare each element's existence in actual list. If it's the second occurrence or more, then index is added in result list.

Does sorted return a copy?

sort() sorts the list and replaces the original list, whereas sorted(list) returns a sorted copy of the list, without changing the original list.

How do you return an index in Python?

The index() method returns the index of the given element in the list. If the element is not found, a ValueError exception is raised.


You can use the python sorting functions' key parameter to sort the index array instead.

>>> s = [2, 3, 1, 4, 5, 3]
>>> sorted(range(len(s)), key=lambda k: s[k])
[2, 0, 1, 5, 3, 4]
>>> 

You can do this with numpy's argsort method if you have numpy available:

>>> import numpy
>>> vals = numpy.array([2,3,1,4,5])
>>> vals
array([2, 3, 1, 4, 5])
>>> sort_index = numpy.argsort(vals)
>>> sort_index
array([2, 0, 1, 3, 4])

If not available, taken from this question, this is the fastest method:

>>> vals = [2,3,1,4,5]
>>> sorted(range(len(vals)), key=vals.__getitem__)
[2, 0, 1, 3, 4]

If you need both the sorted list and the list of indices, you could do:

L = [2,3,1,4,5]
from operator import itemgetter
indices, L_sorted = zip(*sorted(enumerate(L), key=itemgetter(1)))
list(L_sorted)
>>> [1, 2, 3, 4, 5]
list(indices)
>>> [2, 0, 1, 3, 4]

Or, for Python <2.4 (no itemgetter or sorted):

temp = [(v,i) for i,v in enumerate(L)]
temp.sort
indices, L_sorted = zip(*temp)

p.s. The zip(*iterable) idiom reverses the zip process (unzip).


Update:

To deal with your specific requirements:

"my specific need to sort a list of objects based on a property of the objects. i then need to re-order a corresponding list to match the order of the newly sorted list."

That's a long-winded way of doing it. You can achieve that with a single sort by zipping both lists together then sort using the object property as your sort key (and unzipping after).

combined = zip(obj_list, secondary_list)
zipped_sorted = sorted(combined, key=lambda x: x[0].some_obj_attribute)
obj_list, secondary_list = map(list, zip(*zipped_sorted))

Here's a simple example, using strings to represent your object. Here we use the length of the string as the key for sorting.:

str_list = ["banana", "apple", "nom", "Eeeeeeeeeeek"]
sec_list = [0.123423, 9.231, 23, 10.11001]
temp = sorted(zip(str_list, sec_list), key=lambda x: len(x[0]))
str_list, sec_list = map(list, zip(*temp))
str_list
>>> ['nom', 'apple', 'banana', 'Eeeeeeeeeeek']
sec_list
>>> [23, 9.231, 0.123423, 10.11001]

How about

l1 = [2,3,1,4,5]
l2 = [l1.index(x) for x in sorted(l1)]

you can use numpy.argsort

or you can do:

test =  [2,3,1,4,5]
idxs = list(zip(*sorted([(val, i) for i, val in enumerate(test)])))[1]

zip will rearange the list so that the first element is test and the second is the idxs.