260

我有一个数字列表:

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

现在,如果我对这个列表进行排序以获得[1, 2, 3, 5, 100]. 我想要的是排序顺序中原始列表中元素的索引,即[0, 1, 2, 4, 3] --- ala MATLAB 的排序函数,它返回值和索引。

4

15 回答 15

252

如果您使用的是 numpy,则可以使用 argsort() 函数:

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

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

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

于 2012-09-19T00:06:37.833 回答
188

类似下一个:

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

于 2011-06-21T08:58:19.277 回答
87
myList = [1, 2, 3, 100, 5]    
sorted(range(len(myList)),key=myList.__getitem__)

[0, 1, 2, 4, 3]
于 2011-06-21T09:45:44.297 回答
39

我用perfplot(我的一个项目)对这些进行了快速的性能检查,发现除了推荐其他东西之外很难推荐

np.argsort(x)

(注意对数刻度):

在此处输入图像描述


重现情节的代码:

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")
于 2019-07-14T15:45:14.330 回答
25

答案enumerate很好,但我个人不喜欢用于按值排序的 lambda。以下只是反转索引和值,并对其进行排序。所以它会首先按值排序,然后按索引。

sorted((e,i) for i,e in enumerate(myList))
于 2013-07-23T12:48:04.370 回答
14

enumerate用and更新了答案itemgetter

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

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

itemgetteroperator模块中使用:

from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
于 2011-06-21T09:03:05.970 回答
10

本质上你需要做一个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,您可以简单地使用 functionnumpy.argsort或 method 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.
于 2019-08-17T21:35:28.123 回答
7

如果你不想使用 numpy,

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

最快,如此处所示

于 2018-04-25T11:58:01.357 回答
6

其他答案是错误的。

运行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)按预期给出。

于 2019-05-14T08:56:08.207 回答
3

您可以为此目的使用 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)
于 2021-04-16T04:47:15.727 回答
2
s = [2, 3, 1, 4, 5]
print([sorted(s, reverse=False).index(val) for val in s]) 

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

于 2022-01-13T23:03:04.860 回答
2

我们将创建另一个从 0 到 n-1 的索引数组,然后将其压缩到原始数组,然后根据原始值对其进行排序

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

`

于 2019-07-31T20:21:08.387 回答
0

首先将您的列表转换为:

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]]
于 2021-06-18T09:20:31.807 回答
0

代码:

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)

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

于 2021-02-23T08:44:25.897 回答
0

将 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])
于 2019-04-08T17:44:23.690 回答