如何在Python中获得排序数组的索引

我有一个数字列表:

myList = [1, 2, 3, 100, 5]
现在,如果我对这个列表进行排序以获得[1, 2, 3, 5, 100]。 我想要的是元素的下标 原始列表的排序顺序,即[0, 1, 2, 4, 3] ——ala MATLAB的排序函数,返回两者 值和索引。< / p >
336870 次浏览

像下面这样:

>>> myList = [1, 2, 3, 100, 5]
>>> [i[0] for i in sorted(enumerate(myList), key=lambda x:x[1])]
[0, 1, 2, 4, 3]

enumerate(myList)给出了一个包含(index, value)元组的列表:

[(0, 1), (1, 2), (2, 3), (3, 100), (4, 5)]

通过将列表传递给sorted并指定一个函数来提取排序键(每个元组的第二个元素;这就是lambda的作用。最后,使用[i[0] for i in ...]列表推导式提取每个排序元素的原始索引。

更新了enumerateitemgetter的答案:

sorted(enumerate(a), key=lambda x: x[1])
# [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]

压缩列表:元组中的第一个元素是索引,第二个元素是值(然后使用元组的第二个值x[1]对其排序,x是元组)

或者使用__abc1模块`中的itemgetter:

from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
myList = [1, 2, 3, 100, 5]
sorted(range(len(myList)),key=myList.__getitem__)


[0, 1, 2, 4, 3]

如果你使用numpy,你有argsort()函数可用:

>>> import numpy
>>> numpy.argsort(myList)
array([0, 1, 2, 4, 3])

http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html

这将返回对数组或列表进行排序的参数。

enumerate的答案很好,但我个人不喜欢用于按值排序的lambda。下面的操作只是倒转索引和值,并对其排序。首先是按值排序,然后是按下标排序。

sorted((e,i) for i,e in enumerate(myList))

如果您不想使用numpy,

sorted(range(len(seq)), key=seq.__getitem__)

是最快的,如在这里所示。

将numpy导入为np

对指数

S=[11,2,44,55,66,0,10,3,33]


r=np.argsort(S)


[output]=array([5, 1, 7, 6, 0, 8, 2, 3, 4])

argsort按顺序返回S的索引

价值

np.sort(S)


[output]=array([ 0,  2,  3, 10, 11, 33, 44, 55, 66])

其他答案都是错误的。

运行argsort一次不是解决方案。 例如,代码如下:

import numpy as np
x = [3,1,2]
np.argsort(x)

生成array([1, 2, 0], dtype=int64),这不是我们想要的。

答案应该是运行argsort两次:

import numpy as np
x = [3,1,2]
np.argsort(np.argsort(x))

给出array([2, 0, 1], dtype=int64)

我用perfplot(我的一个项目)对这些做了一个快速的性能检查,发现很难推荐其他任何东西

np.argsort(x)

(注意对数刻度):

enter image description here


代码重现情节:

import perfplot
import numpy as np




def sorted_enumerate(seq):
return [i for (v, i) in sorted((v, i) for (i, v) in enumerate(seq))]




def sorted_enumerate_key(seq):
return [x for x, y in sorted(enumerate(seq), key=lambda x: x[1])]




def sorted_range(seq):
return sorted(range(len(seq)), key=seq.__getitem__)




b = perfplot.bench(
setup=np.random.rand,
kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, np.argsort],
n_range=[2 ** k for k in range(15)],
xlabel="len(x)",
)
b.save("out.png")
我们将创建另一个从0到n-1的索引数组 然后将其压缩到原始数组,然后根据原始值

对其排序
ar = [1,2,3,4,5]
new_ar = list(zip(ar,[i for i in range(len(ar))]))
new_ar.sort()

本质上,你需要做一个argsort,你需要什么实现取决于你是想使用外部库(例如NumPy),还是想保持纯python而不依赖。

你需要问自己的问题是:你想要

  • 对数组/列表进行排序的索引
  • 元素在排序后的数组/列表中的下标

不幸的是,问题中的例子并没有说清楚我们想要什么,因为两者都会给出相同的结果:

>>> arr = np.array([1, 2, 3, 100, 5])


>>> np.argsort(np.argsort(arr))
array([0, 1, 2, 4, 3], dtype=int64)


>>> np.argsort(arr)
array([0, 1, 2, 4, 3], dtype=int64)

选择argsort实现

如果你有NumPy,你可以简单地使用函数numpy.argsort或方法numpy.ndarray.argsort

没有NumPy的实现已经在其他一些答案中提到过,所以我只是根据这里的基准答案概括一下最快的解决方案

def argsort(l):
return sorted(range(len(l)), key=l.__getitem__)

获取对数组/列表进行排序的下标

要获得对数组/列表排序的下标,只需在数组或列表上调用argsort。我在这里使用的是NumPy版本,但Python实现应该会给出相同的结果

>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(arr)
array([1, 2, 0, 3], dtype=int64)

结果包含获取排序数组所需的下标。

由于已排序的数组为[1, 2, 3, 4],因此argsorted数组包含原始数组中这些元素的下标。

  • 最小的值是1,它在原始索引1处,因此结果的第一个元素是1
  • 2位于原函数的2索引处,因此结果的第二个元素是2
  • 3在原函数的索引0处,因此结果的第三个元素是0
  • 最大的值4,它在原始索引3处,因此结果的最后一个元素是3

获取元素在排序后的数组/列表中的下标

在这种情况下,你需要应用argsort 两次:

>>> arr = np.array([3, 1, 2, 4])
>>> np.argsort(np.argsort(arr))
array([2, 0, 1, 3], dtype=int64)

在这种情况下:

  • 原数组的第一个元素是3,这是第三大的值,因此它在已排序的数组/列表中有2索引,因此第一个元素是2
  • 原数组的第二个元素是1,它是最小的值,因此在排序数组/列表中它的索引是0,因此第二个元素是0
  • 原数组的第三个元素是2,这是第二个最小的值,因此它在排序数组/列表中的索引是1,因此第三个元素是1
  • 原始数组的第四个元素是4,它是最大的值,因此在排序数组/列表中它的索引是3,因此最后一个元素是3

代码:

s = [2, 3, 1, 4, 5]
li = []


for i in range(len(s)):
li.append([s[i], i])
li.sort()
sort_index = []


for x in li:
sort_index.append(x[1])


print(sort_index)

试试这个,对我有用,干杯!

最简单的方法,你可以使用Numpy包的目的:

import numpy
s = numpy.array([2, 3, 1, 4, 5])
sort_index = numpy.argsort(s)
print(sort_index)

但是如果你想要你的代码应该使用baisc python代码:

s = [2, 3, 1, 4, 5]
li=[]
  

for i in range(len(s)):
li.append([s[i],i])
li.sort()
sort_index = []
  

for x in li:
sort_index.append(x[1])
  

print(sort_index)

首先把你的列表转换成这样:

myList = [1, 2, 3, 100, 5]

为列表的项添加索引

myList = [[0, 1], [1, 2], [2, 3], [3, 100], [4, 5]]

下一个:

sorted(myList, key=lambda k:k[1])

结果:

[[0, 1], [1, 2], [2, 3], [4, 5], [3, 100]]
s = [2, 3, 1, 4, 5]
print([sorted(s, reverse=False).index(val) for val in s])

它甚至适用于具有重复元素的列表。