Ответ 1
Вы можете использовать параметр сортировки python 'key
для сортировки массива индекса.
>>> s = [2, 3, 1, 4, 5]
>>> sorted(range(len(s)), key=lambda k: s[k])
[2, 0, 1, 3, 4]
>>>
Мне нужно отсортировать список, а затем вернуть список с индексом отсортированных элементов в списке. Например, если список, который я хочу сортировать, [2,3,1,4,5]
, мне нужно вернуть [2,0,1,3,4]
.
Этот вопрос был отправлен по байтам, но я думал, что я его перепечатаю здесь. http://bytes.com/topic/python/answers/44513-sorting-list-then-return-index-sorted-item
Мне нужна сортировка списка объектов на основе свойств объектов. Затем мне нужно переупорядочить соответствующий список, чтобы он соответствовал порядку нового отсортированного списка.
Есть ли хороший способ сделать это?
Вы можете использовать параметр сортировки python 'key
для сортировки массива индекса.
>>> s = [2, 3, 1, 4, 5]
>>> sorted(range(len(s)), key=lambda k: s[k])
[2, 0, 1, 3, 4]
>>>
Вы можете сделать это с помощью метода 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]
Если вам нужен как отсортированный список, так и список индексов, вы можете сделать:
>>> 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]
Как насчет
l1 = [2,3,1,4,5]
l2 = [l1.index(x) for x in sorted(l1)]
Вы можете использовать numpy.argsort
или вы можете сделать:
test = [2,3,1,4,5]
idxs = list(zip(*sorted([(val, i) for i, val in enumerate(test)])))[1]
zip
перегруппирует список так, что первый элемент будет test
а второй - idxs
.
Что я буду делать, глядя на ваши конкретные потребности:
Скажите, что у вас есть список a
с некоторыми значениями, а ваши ключи находятся в атрибуте x
объектов, хранящихся в списке b
keys = {i:j.x for i,j in zip(a, b)}
a.sort(key=keys.__get_item__)
С помощью этого метода вы получите свой список, не создавая список промежуточных перестановок, о котором вы просите.
Из документации для 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.