Сортировка по произвольным элементам вложенных списков
В Python можно выполнить сортировку списка на месте с помощью метода sort()
:
>>> a = [10,3,4,1,9]
>>> a.sort()
>>> a
[1, 3, 4, 9, 10]
Отметим, что есть аналогичная списковому методу sort()
встроенная функция sorted()
, которая не изменяет последовательность, а возвращает новую отсортированную.
Если элементы списка сами представляют собой списки, т. е. являются вложенными списками, то сортировка будет происходить по первым элементам вложенных списков, то есть в случае матрицы по первому столбцу:
>>> a = [[12,101],[2,200],[18,99]]
>>> a.sort()
>>> a
[[2, 200], [12, 101], [18, 99]]
Что делать, если надо отсортировать не по первому столбцу? На этот случай sort()
принимает необязательный аргумент key
, в котором передается другая функция. Этой другой функции передается очередной элемент списка. Она может сделать с ним что угодно и вернуть что угодно. По этому "что угодно" и происходит сортировка.
Так, например, пользовательская функция может возвращать из переданного ей элемента, представляющего собой вложенный список, любой элемент этого вложенного списка. В свою очередь функция sort()
будет сортировать по тем значениям, которые ей возвращаются.
В качестве примера приведем программу, в которой список представляет собой маленькую базу данных. Допустим, каждый элемент содержит сведения о юном спортсмене: имя, возраст, рост и вес. Пользователь может заказать сортировку по любому полю:
a = [['петя',10,130,35], ['вася',11,135,39],
['женя',9,140,33],['дима',10,128,30]]
n = input('Сортировать по имени (1),
возрасту (2), росту (3), весу (4): ')
n = int(n)-1
def sort_col(i):
return i[n]
a.sort(key=sort_col)
for i in a:
print("%7s %3d %4d %3d" % (i[0],i[1],i[2],i[3]))
Здесь пользователь вводит номер поля. Число приводится к типу int
, и из него вычитается единица, т. к. индексация списка начинается с нуля.
Далее определяется функция sort_col()
. Ей передается аргумент i, а она возвращает n-ый элемент этого аргумента. Так, если этой функции передать вложенный список, то она вернет его n-й элемент. В данном случае тот, который хотел пользователь.
В функции sort()
указывается пользовательская функция. Когда sort()
извлекает очередной элемент списка, в данном случае - вложенный список, то передает этой функции. Получается, что элемент списка подменяется на то, что возвращает пользовательская функция.
В данном случае если пользователь заказывает сортировку по второму столбцу, вывод будет таким:
Сортировать по имени (1), возрасту (2),
росту (3), весу (4): 2
женя 9 140 33
петя 10 130 35
дима 10 128 30
вася 11 135 39
Можно не определять обычную функцию, а использовать lambda-функцию:
a = [['петя',10,130,35], ['вася',11,135,39],
['женя',9,140,33],['дима',10,128,30]]
n = input('Сортировать по имени (1),
возрасту (2), росту (3), весу (4): ')
n = int(n)-1
a.sort(key=lambda i: i[n])
for i in a:
print("%7s %3d %4d %3d"
% (i[0],i[1],i[2],i[3]))
Кроме того, метод sort()
имеет еще один необязательный параметр по ключевому слову - reverse
. По умолчанию он равен False
. Это значит, что сортировка происходит по возрастанию. Однако если у reverse
будет значение True
, то сортировка будет обратной, т. е. по убыванию. В измененной программе ниже реализована возможность выбора типа сортировки:
a = [['петя',10,130,35], ['вася',11,135,39],
['женя',9,140,33],['дима',10,128,30]]
n = input('Сортировать по имени (1),
возрасту (2), росту (3), весу (4): ')
n = int(n)-1
t = input('По возрастанию (0), по убыванию (1): ')
t = int(t)
a.sort(key=lambda i: i[n], reverse=t)
for i in a:
print("%7s %3d %4d %3d"
% (i[0],i[1],i[2],i[3]))
При сортировке по весу по убыванию получим:
Сортировать по имени (1), возрасту (2),
росту (3), весу (4): 4
По возрастанию (0), по убыванию (1): 1
вася 11 135 39
петя 10 130 35
женя 9 140 33
дима 10 128 30