Подтвердить что ты не робот

Как вернуть индекс отсортированного списка?

Мне нужно отсортировать список, а затем вернуть список с индексом отсортированных элементов в списке. Например, если список, который я хочу сортировать, [2,3,1,4,5], мне нужно вернуть [2,0,1,3,4].

Этот вопрос был отправлен по байтам, но я думал, что я его перепечатаю здесь. http://bytes.com/topic/python/answers/44513-sorting-list-then-return-index-sorted-item

Мне нужна сортировка списка объектов на основе свойств объектов. Затем мне нужно переупорядочить соответствующий список, чтобы он соответствовал порядку нового отсортированного списка.

Есть ли хороший способ сделать это?

4b9b3361

Ответ 1

Вы можете использовать параметр сортировки python 'key для сортировки массива индекса.

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

Ответ 2

Вы можете сделать это с помощью метода numpy argsort, если у вас есть numpy:

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

Если этот параметр недоступен, взятый из этого вопроса, это самый быстрый способ:

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

Ответ 3

Если вам нужен как отсортированный список, так и список индексов, вы можете сделать:

>>> 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 (no itemgetter или sorted):

>>> temp = [(v,i) for i,v in enumerate(L)]
>>> temp.sort
>>> indices, L_sorted = zip(*temp)

p.s. Идиома zip(*iterable) отменяет процесс zip (unzip).


Обновление:

Для решения ваших конкретных требований:

"моя конкретная необходимость сортировать список объектов на основе свойства объектов. Затем мне нужно переупорядочить соответствующий список, чтобы он соответствовал порядку нового отсортированного списка."

Это длинный способ сделать это. Вы можете достичь этого с помощью одного вида, объединив оба списка вместе, затем выполните сортировку с использованием свойства объекта в качестве ключа сортировки (и разархивируйте его после).

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]

Ответ 4

Как насчет

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

Ответ 5

Вы можете использовать numpy.argsort

или вы можете сделать:

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

zip перегруппирует список так, что первый элемент будет test а второй - idxs.

Ответ 6

Что я буду делать, глядя на ваши конкретные потребности:

Скажите, что у вас есть список a с некоторыми значениями, а ваши ключи находятся в атрибуте x объектов, хранящихся в списке b

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

С помощью этого метода вы получите свой список, не создавая список промежуточных перестановок, о котором вы просите.

Ответ 7

Из документации для 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.