Язык Python предоставляет
довольно гибкий механизм для сортировки элементов упорядоченных коллекций. И
реализуется, в основном, или встроенным методом списков
sort()
или функцией
sorted()
для всех
остальных типов коллекций. Давайте вначале посмотрим на отличие в их вызовах. Если
у нас имеется какой-либо упорядоченный список:
то этот объект
имеет встроенный метод sort, который меняет его состояние и
расставляет элементы по возрастанию:
Получим
измененный список:
[-45, -4, 1, 2, 3, 100]
А вот коллекции
кортежи или строки:
b=("ab", "bc", "wd", "gf")
c = "hello world"
не имеют такого
встроенного метода и попытка их отсортировать, записав:
приведет к
ошибке. Для их сортировки как раз и можно воспользоваться второй функцией sorted:
на выходе
получим упорядоченный список
['ab',
'bc', 'gf', 'wd']
Обратите
внимание, чтобы мы не передавали в качестве аргумента функции sorted, на выходе будем
получать именно список отсортированных данных. В данном случае передаем кортеж,
а получаем – список.
Или же, со
строкой:
результатом будет
упорядоченная коллекция из символов:
[' ',
'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
Причем, эта
функция не меняет исходные коллекции b и c, она возвращает
новый список с отсортированными данными. В то время как метод sort для списка
меняет этот список. Вот на это следует также обращать внимание. То есть, если
нам нужно сохранить результат сортировки в переменной, это делается так:
и res будет ссылаться
на список:
['ab',
'bc', 'gf', 'wd']
Также следует
иметь в виду, что сортировка данных возможна для однотипных элементов: или
чисел, или строк, или кортежей, но не их комбинаций. Например, вот такой
список:
a=[1,-45,3,2,100,-4, "b"]
отсортировать не
получится:
возникнет
ошибка, что строку нельзя сравнивать с числом. И то же самое с функцией sorted:
Если уберем
последний элемент:
то все будет
работать:
И этот пример
также показывает, что список можно сортировать и с помощью метода sort и с помощью
функции sorted. Разница только
в том, что метод sort не создает новой коллекции, а меняет уже
существующую. Функция же sorted не меняет
исходную коллекцию, а создает новую с отсортированными элементами. Поэтому, для
изменения коллекции a здесь следует записывать такую конструкцию:
Оба этих подхода
к сортировке поддерживают необязательный параметр
reverse = True/False
который
определяет порядок сортировки: по возрастанию (False) или по
убыванию (True). По умолчанию
стоит значение reverse=False. Если мы
запишем его вот так:
a = sorted(a, reverse=True)
то получим
сортировку по убыванию:
[100,
3, 2, 1, -4, -45]
И то же самое с
методом sort:
Своя сортирующая функция
Язык Python позволяет
создавать свои сортирующие функции для более точной настройки алгоритма
сортировки. Давайте для начала рассмотрим такой пример. Пусть у нас имеется вот
такой список:
и мы хотим,
чтобы вначале стояли четные элементы, а в конце – нечетные. Для этого создадим
такую вспомогательную функцию:
def funcSort(x):
return x%2
И укажем ее при
сортировке:
print( sorted(a, key=funcSort) )
Мы здесь
используем именованный параметр key, который принимает ссылку на
сортирующую функцию. Запускаем программу и видим следующий результат:
[4,
6, 2, 1, 3, 5]
Разберемся,
почему так произошло. Смотрите, функция funcSort возвращает вот
такие значения для каждого элемента списка a:
И, далее, в sorted уже
используются именно эти значения для сортировки элементов по возрастанию. То
есть, сначала, по порядку берется элемент со значением 4, затем, 6 и потом 2.
После этого следуют нечетные значения в порядке их следования: 1, 3, 5. В
результате мы получаем список:
[4, 6, 2, 1, 3,
5]
А теперь,
давайте модифицируем нашу функцию, чтобы выполнялась сортировка и самих
значений:
def funcSort(x):
if x%2 == 0:
return x
else:
return x+100
Здесь четные
значения возвращаются такими как они есть, а к нечетным прибавляем 100. В
результате получим:
[2,
4, 6, 1, 3, 5]
Здесь элементам
нашего списка ставятся в соответствие указанные числа, и по этим числам
выполняется их сортировка. То есть, эти числа можно воспринимать как некие
ключи, по которым и происходит сортировка элементов списка. Поэтому в Python
такую
сортировку называют сортировкой по ключам.
Конечно, здесь
вместо определения своей функции можно также записывать анонимные функции,
например:
print( sorted(a, key=lambda x: x%2) )
Получим ранее
рассмотренный результат:
[4, 6, 2, 1, 3,
5]
Или, то же самое
можно делать и со строками:
lst = ["Москва", "Тверь", "Смоленск", "Псков", "Рязань"]
Отсортируем их
по длине строки:
print( sorted(lst, key=len) )
получим
результат:
['Тверь',
'Псков', 'Москва', 'Рязань', 'Смоленск']
Или по
последнему символу, используя лексикографический порядок:
print( sorted(lst, key=lambda x: x[-1]) )
['Москва',
'Псков', 'Смоленск', 'Тверь', 'Рязань']
Или, по первому
символу:
print( sorted(lst, key=lambda x: x[0]) )
['Москва',
'Псков', 'Рязань', 'Смоленск', 'Тверь']
И так далее. Этот
подход часто используют при сортировке сложных структур данных. Допустим, у нас
имеется вот такой список из книг:
books = {
("Евгений Онегин", "Пушкин А.С.", 200),
("Муму", "Тургенев И.С.", 250),
("Мастер и Маргарита", "Булгаков М.А.", 500),
("Мертвые души", "Гоголь Н.В.", 190)
}
И нам нужно его
отсортировать по возрастанию цены (последнее значение). Это можно сделать так:
print( sorted(books, key=lambda x: x[2]) )
На выходе
получим список:
[('Мертвые
души', 'Гоголь Н.В.', 190), ('Евгений Онегин', 'Пушкин А.С.', 200), ('Муму',
'Тургенев И.С.', 250), ('Мастер и Маргарита', 'Булгаков М.А.', 500)]
Вот так можно
выполнять сортировку данных в Python.
Задания для самоподготовки
1. Используя
сортировку, найдите первые три наименьшие значения в списке:
a=[1,2,-5,0,5,10]
Сам список
должен оставаться неизменным.
2. Отсортируйте
список:
digs
= (-10, 0, 7, -2, 3, 6, -8)
так, чтобы
сначала шли отрицательные числа, а затем, положительные.
3. Пусть имеется
словарь:
{'+7':
2345678901, '+4': 3456789012, '+5': 5678901234, '+12': 78901234}
Необходимо
вывести телефонные номера по убыванию чисел, указанных в ключах, то есть, в
порядке:
+4, +5, +7, +12