如何返回已排序列表的索引?

我需要对一个列表进行排序,然后返回一个包含列表中已排序项的索引的列表。例如,如果我想排序的列表是 [2,3,1,4,5],我需要返回 [2,0,1,3,4]

这个问题是以字节的形式发布的,但是我想我应该把它转发到这里。 Http://bytes.com/topic/python/answers/44513-sorting-list-then-return-index-sorted-item

我特别需要根据对象的属性对对象列表进行排序。然后,我需要重新排序相应的列表,以匹配新排序的列表的顺序。

有什么好办法吗?

278898 次浏览

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

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

如果你同时需要排序列表和索引列表,你可以这样做:

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) :

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

P.s. zip(*iterable)习惯用法逆转 zip 进程(解压缩)。


更新:

处理你的具体要求:

”我特别需要根据对象的属性对对象列表进行排序。然后,我需要重新排列一个相应的列表,以便与新排序的列表的顺序相匹配。”

真是冗长的做法。通过将两个列表压缩在一起,然后使用对象属性作为排序键进行排序(然后解压缩) ,可以通过单一排序实现这一点。

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))

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

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]

看到你的特殊需求,我会怎么做:

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

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

使用这种方法,您可以获得排序列表,而不必构造您要求的中间置换列表。

怎么样

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

你可以使用 numpy.argsort

或者你可以这样做:

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

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

如果有 numpy 可用,可以使用 numpy 的 Argsort方法:

>>> 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])

如果不可用,从 这个问题中提取,这是最快的方法:

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

这是 collections.OrderedDict的文件:

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

改编自原文中的例子:

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