Как получить индексы отсортированного массива в Python
У меня есть числовой список:
myList = [1, 2, 3, 100, 5]
Теперь, если я отсортирую этот список для получения [1, 2, 3, 5, 100]
.
Я хочу индексы элементов из
исходный список в отсортированном порядке, т.е. [0, 1, 2, 4, 3]
--- ala Функция сортировки MATLAB, которая возвращает оба
значений и индексов.
Ответы
Ответ 1
Если вы используете numpy, у вас есть доступная функция argsort():
>>> import numpy
>>> numpy.argsort(myList)
array([0, 1, 2, 4, 3])
http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html
Это возвращает аргументы, которые будут сортировать массив или список.
Ответ 2
Что-то вроде следующего:
>>> 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 ...]
.
Ответ 3
myList = [1, 2, 3, 100, 5]
sorted(range(len(myList)),key=myList.__getitem__)
[0, 1, 2, 4, 3]
Ответ 4
Ответы с enumerate
хороши, но мне лично не нравится, что лямбда используется для сортировки по значению. Следующие просто меняют индекс и значение и сортируют его. Поэтому сначала он сортируется по значению, затем по индексу.
sorted((e,i) for i,e in enumerate(myList))
Ответ 5
Обновлен ответ с помощью enumerate
и itemgetter
:
sorted(enumerate(a), key=lambda x: x[1])
# [(0, 1), (1, 2), (2, 3), (4, 5), (3, 100)]
Запишите списки вместе: первый элемент в кортеже будет индексом, второй - значением (затем отсортируйте его, используя второе значение кортежа x[1]
, x - кортеж)
Или используя itemgetter
из модуля operator
:
from operator import itemgetter
sorted(enumerate(a), key=itemgetter(1))
Ответ 6
Если вы не хотите использовать NumPy,
sorted(range(len(seq)), key=seq.__getitem__)
самый быстрый, как показано здесь.
Ответ 7
Я быстро проверил их производительность с помощью 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,
)
Ответ 8
Другие ответы НЕПРАВИЛЬНЫ.
Запуск 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)
как и ожидалось.
Ответ 9
По сути, вам нужно сделать 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
.
Ответ 10
Импортировать 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])
Ответ 11
Мы создадим еще один массив индексов от 0 до n-1
Затем заархивируйте его в исходный массив, а затем отсортируйте его на основе исходных значений
ar = [1,2,3,4,5]
new_ar = list(zip(ar,[i for i in range(len(ar))]))
new_ar.sort()
"