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

Список сортировки в Python двумя другими списками

Мой вопрос очень похож на эти две ссылки 1 и 2:

У меня есть три разных списка. Я хочу сортировать List1 на основе List2 (в порядке возрастания). Однако у меня есть повторы в List2. Затем я хочу отсортировать эти повторы List3 (в порядке убывания). Достаточно сложно?

Что у меня:

List1 = ['a', 'b', 'c', 'd', 'e']
List2 = [4, 2, 3, 2, 4]
List3 = [0.1, 0.8, 0.3, 0.6, 0.4]

Что я хочу:

new_List1 = ['b', 'd', 'c', 'e', 'a']

'b' предшествует 'd', так как 0.8 > 0.6. 'e' приходит до 'a' с 0,4 > 0,1.

Любая помощь?

Спасибо!

4b9b3361

Ответ 1

Думаю, вы сможете это сделать:

paired_sorted = sorted(zip(List2,List3,List1),key = lambda x: (x[0],-x[1]))
l2,l3,l1 = zip(*paired_sorted)

В действии:

>>> List1 = ['a', 'b', 'c', 'd', 'e']
>>> List2 = [4, 2, 3, 2, 4]
>>> List3 = [0.1, 0.8, 0.3, 0.6, 0.4]
>>> paired_sorted = sorted(zip(List2,List3,List1),key = lambda x: (x[0],-x[1]))
>>> l2,l3,l1 = zip(*paired_sorted)
>>> print l1
('b', 'd', 'c', 'e', 'a')

Вот как это работает. Сначала мы сопоставляем соответствующие элементы из ваших списков с помощью zip. Затем мы сортируем эти элементы на основе элементов из List2 сначала и (отрицаем) List3 second. Затем нам просто нужно снова снять элементы List1 с помощью zip и распаковки аргументов. Хотя вы могли бы сделать это легко со списком, если бы вы хотели убедиться, что у вас есть список в конце дня, а не кортеж.

Это становится немного сложнее, если вы не можете легко отменить значения в List3 - например. если они строки. Вам необходимо выполнить сортировку за 2 прохода:

paired = zip(List2,List3,List1)
rev_sorted = sorted(paired,reverse=True,key=lambda x: x[1])  #"minor" sort first
paired_sorted = sorted(rev_sorted,key=lambda x:x[0])         #"major" sort last
l2,l3,l1 = zip(*paired_sorted)

(вы можете использовать operator.itemgetter(1) вместо lambda x:x[1] в приведенном выше примере, если хотите). Это работает, потому что сортировка python является "стабильной". Он не переупорядочивает "равные" элементы.

Ответ 2

Для этого требуется этап decorate-sort-undecorate:

decorated = zip(List1, List2, List3)
decorated.sort(key=lambda v: (v[1], -v[2]))
new_list1 = [v[0] for v in decorated]

или, объединенные в одну строку:

new_list1 = [v[0] for v in sorted(zip(List1, List2, List3), key=lambda v: (v[1], -v[2]))]

Вывод:

>>> List1 = ['a', 'b', 'c', 'd', 'e']
>>> List2 = [4, 2, 3, 2, 4]
>>> List3 = [0.1, 0.8, 0.3, 0.6, 0.4]
>>> new_list1 = [v[0] for v in sorted(zip(List1, List2, List3), key=lambda v: (v[1], -v[2]))]
>>> new_list1
['b', 'd', 'c', 'e', 'a']

Ответ 3

>>> [v for i, v in sorted(enumerate(List1), key=lambda i_v: (List2[i_v[0]], -List3[i_v[0]]))]
['b', 'd', 'c', 'e', 'a']

Сортирует пары index/value, используя индексы, чтобы получить соответствующие значения из других списков для использования в ключевой функции, используемой для упорядочивания с помощью sorted(), а затем извлекает только значения, используя понимание списка.

Вот более короткая альтернатива, которая сортирует только индексы и затем использует эти индексы для захвата значений из List1:

>>> [List1[i] for i in sorted(range(len(List1)), key=lambda i: (List2[i], -List3[i]))]
['b', 'd', 'c', 'e', 'a']