Иногда возникает необходимость сортировать не только числовые последовательности, но и более сложные объекты, а также сохранять при сортировке знание о позиции элемента в исходной последовательности. Всё это в языки Python делается довольно просто и элегантно.

Начнём с того, что Python умеет сравнивать списки:

>>> [1, 2, 3, 4] > [2, 3, 4]
False
>>> [1, 2, 3, 4] > [1, 2, 3, 4]
False
>>> [1, 3, 2, 4] > [1, 2, 3, 4]
True
>>> [1, 2, 3, 4, 5] > [1, 2, 3, 4]
True
>>> [10] > [1, 2, 3, 4]
True
>>> [2, -100] > [1, 2, 3, 4]
True
Сравнивает он их поэлементно (или лексикографически), то есть сначала сравнивает первые элементы. Владелец большего первого элемента и сам больше. Если же первые элементы совпадают, то мы сравниваем вторые элементы. Так мы движемся до тех пор, пока i-й элемент одного списка не станет больше i-го элемента второго списка, тогда первый победит. Если какой-то список закончился раньше, то он меньше. А иначе списки совпадают.

Итак, если списки можно сравнивать, то их можно и сортировать.

>>> A = [[1, 2, 3, 4], [2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4, 5], [10], [2, -100], [1, 3, 2, 4], [1, 2, 3, 4]]
>>> sorted(A)
[[1, 2, 3, 4],
 [1, 2, 3, 4],
 [1, 2, 3, 4],
 [1, 2, 3, 4, 5],
 [1, 3, 2, 4],
 [2, -100],
 [2, 3, 4],
 [10]]

Конечно же, для того, чтобы такой «сложный» список можно было отсортировать, необходимо, чтобы его элементы можно было сравнить.

>>> sorted([[1, 2], [1, 'a']])
Traceback (most recent call last):
  File "< string >", line 301, in runcode
  File "< interactive input >", line 1, in < module >
TypeError: unorderable types: str() < int()

Теперь представим себе, что нам нужно отсторировать список, но при этом нужно сохнанить знание о том, где стоял элемент до сортировки. Для этого можно применить такой трюк: заменим число x на кортеж (x, i), где i — номер элемента в списке. И после этого отсортируем.

my_list = [39, 12, 21, 77, 21, 51, 48, 21, 42, 76]
for i in range(len(my_list)):
    my_list[i] = (my_list[i], i)
my_list.sort()
print(my_list)

[(12, 1), (21, 2), (21, 4), (21, 7), (39, 0), (42, 8), (48, 6), (51, 5), (76, 9), (77, 3)]

Благодаря такой операции мы знаем, что числа 21 стояли на 2, 4 и 7-й позиции в исходном списке, а наибольшее число 77 было на позиции 3. Всё это можно сделать короче с помощью генератора списков:

my_list = [39, 12, 21, 77, 21, 51, 48, 21, 42, 76]
hacked_list = sorted([(my_list[i], i) for i in range(len(my_list))])
Последнее изменение: Суббота, 15 Август 2020, 02:35