Как получить индексы отсортированного массива в Python - PullRequest
166 голосов
/ 21 июня 2011

У меня есть числовой список:

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

Теперь, если я отсортирую этот список, получим [1, 2, 3, 5, 100]. То, что я хочу, это индексы элементов из исходный список в отсортированном порядке, т.е. [0, 1, 2, 4, 3] --- функция сортировки аля MATLAB, которая возвращает оба ценности и показатели.

Ответы [ 9 ]

158 голосов
/ 19 сентября 2012

Если вы используете numpy, у вас есть доступная функция argsort ():

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

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

Возвращает аргументы для сортировки массива или списка.

121 голосов
/ 21 июня 2011

Что-то вроде следующего:

>>> 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) дает вам список, содержащий кортежи (индекс, значение):

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

Вы сортируете список, передавая его sorted и указание функции для извлечения ключа сортировки (второй элемент каждого кортежа; для этого и нужен lambda. Наконец, исходный индекс каждого отсортированного элемента извлекается с использованием [i[0] for i in ...]понимание списка.

65 голосов
/ 21 июня 2011
myList = [1, 2, 3, 100, 5]    
sorted(range(len(myList)),key=myList.__getitem__)

[0, 1, 2, 4, 3]
18 голосов
/ 23 июля 2013

Ответы с enumerate хороши, но мне лично не нравится лямбда, используемая для сортировки по значению. Следующее просто инвертирует индекс и значение и сортирует их. Так что сначала он будет отсортирован по значению, а затем по индексу.

sorted((e,i) for i,e in enumerate(myList))
11 голосов
/ 21 июня 2011

Обновлен ответ с enumerate и itemgetter:

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

Объединить списки в один список: первый элемент в кортеже будет индексом, второй - значением (затем отсортировать его с помощью второгозначение кортежа x[1], х - кортеж)

или использование itemgetter из operator module`:

from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
4 голосов
/ 25 апреля 2018

Если вы не хотите использовать numpy,

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

самый быстрый, как продемонстрировано здесь .

2 голосов
/ 14 мая 2019

Другие ответы НЕПРАВИЛЬНЫ.

Запуск 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), как и ожидалось.

0 голосов
/ 14 июля 2019

Я быстро проверил их производительность с помощью perfplot (мой проект) и обнаружил, что трудно порекомендовать что-либо еще, кроме numpy (обратите внимание на масштаб журнала):

enter image description here


Код для воспроизведения сюжета:

import perfplot
import numpy


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


def numpy_argsort(x):
    return numpy.argsort(x)


perfplot.save(
    "argsort.png",
    setup=lambda n: numpy.random.rand(n),
    kernels=[sorted_enumerate, sorted_enumerate_key, sorted_range, numpy_argsort],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(x)",
    logx=True,
    logy=True,
)
0 голосов
/ 08 апреля 2019

Импортировать 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])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...