关于python:如何返回排序列表的索引?

how to return index of a sorted list?

本问题已经有最佳答案,请猛点这里访问。

我需要对列表进行排序,然后返回带有列表中已排序项目的索引的列表。 例如,如果要排序的列表是[2,3,1,4,5],则需要返回[2,0,1,3,4]

这个问题以字节为单位发布,但我想我会在这里重新发布。
http://bytes.com/topic/python/answers/44513-sorting-list-then-return-index-sorted-item

我的具体需求是根据对象的属性对对象列表进行排序。 然后,我需要重新排序对应的列表以匹配新排序的列表的顺序。

有什么好方法吗?


您可以使用python排序函数的key参数来对索引数组进行排序。

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

如果您有可用的numpy,可以使用numpy的argsort方法执行此操作:

1
2
3
4
5
6
7
>>> 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])

如果不可行,从这个问题中得出,这是最快的方法:

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


如果同时需要排序列表和索引列表,则可以执行以下操作:

1
2
3
4
5
6
7
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]

或者,对于Python <2.4(无itemgettersorted):

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

ps。 zip(*iterable)惯用语反转了zip进程(解压缩)。

更新:

要满足您的特定要求:

"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."

这是一个漫长的做法。您可以通过将两个列表都压缩在一起,然后使用object属性作为您的排序键进行排序(然后再解压缩),从而实现一次排序。

1
2
3
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))

这是一个简单的示例,使用字符串表示您的对象。在这里,我们使用字符串的长度作为排序的键:

1
2
3
4
5
6
7
8
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]

怎么样

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


您可以使用numpy.argsort

或者您可以执行以下操作:

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

zip将重新排列列表,以便第一个元素是test,第二个元素是idxs


我会做的,看看您的特定需求:

假设您的列表a具有一些值,并且键位于列表b中存储的对象的属性x

1
2
keys = {i:j.x for i,j in zip(a, b)}
a.sort(key=keys.__get_item__)

使用此方法,您可以将列表排序,而不必构造您要的中间排列列表。


直接出自collections.OrderedDict的文档:

1
2
3
>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

适应原始帖子中的示例:

1
2
3
>>> l=[2,3,1,4,5]
>>> OrderedDict(sorted(enumerate(l), key=lambda x: x[1])).keys()
[2, 0, 1, 3, 4]

有关详细信息,请参见http://docs.python.org/library/collections.html#collections.OrderedDict。