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

时间:2011-10-21 14:43:23

标签: python

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

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

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

有没有好办法呢?

7 个答案:

答案 0 :(得分:178)

您可以使用python排序函数'key参数来代替索引数组。

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

答案 1 :(得分:64)

如果您有可用的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])

如果不可用,取自this question,这是最快的方法:

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

答案 2 :(得分:11)

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

>>> 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进程(解压缩)。


更新

处理您的具体要求:

  

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

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

zipped = 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]

答案 3 :(得分:7)

怎么样

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

答案 4 :(得分:0)

我会做什么,看看你的具体需求:

假设您的列表a包含一些值,并且您的密钥位于列表x中存储的对象的属性b

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

使用此方法,您可以获得订单,而无需构建您要求的中间排列列表。

答案 5 :(得分:0)

您可以使用numpy.argsort

或者你可以这样做:

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

答案 6 :(得分:-2)

直接退出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