Сортировка в Python: sort(), sorted(), параметр key и lambda
Этот урок переведён с английского оригинала.Read in EnglishLeer en españolСообщить об ошибке в переводе
Представьте книжную полку у себя дома. Книги стоят как попало: одни по названию, другие по цвету, третьи засунуты боком. На поиски нужной уходит целая вечность.
А теперь представьте, что вы расставили книги по алфавиту. Теперь любая книга находится за секунды. В этом и сила сортировки: она превращает хаос в порядок.
Для сортировки в Python есть два основных инструмента: метод sort() и функция sorted(). Они похожи, но работают по-разному. В этом уроке вы узнаете, когда использовать каждый из них, как сортировать в обратном порядке и как задавать собственные правила сортировки с помощью функций-ключей.
Чем sort() отличается от sorted()?
Это самое важное различие в сортировке на Python. Метод sort() меняет исходный список напрямую. Функция sorted() создаёт совершенно новый отсортированный список, а исходный не трогает.
Представьте это так: sort() переставляет книги на самой полке, а sorted() составляет упорядоченный каталог и оставляет полку в точности такой, какой она была.
[1, 2, 5, 8, 9]
[1, 2, 5, 8, 9] [5, 2, 8, 1, 9]
names = ['Charlie', 'Alice', 'Bob']
result = names.sort()
print(result) # None!names = ['Charlie', 'Alice', 'Bob']
result = sorted(names)
print(result) # ['Alice', 'Bob', 'Charlie']Есть и ещё одно важное отличие: sorted() работает с любым итерируемым объектом, будь то строки, кортежи, словари или даже генераторы. Метод sort() работает только со списками.
['h', 'n', 'o', 'p', 't', 'y'] [1, 1, 3, 4, 5]
Как сортировать в обратном порядке
И sort(), и sorted() принимают параметр reverse. Задайте ему значение True, чтобы сортировать от большего к меньшему, а не от меньшего к большему.
[61, 72, 88, 95, 100] [100, 95, 88, 72, 61]
Строки по умолчанию сортируются по алфавиту. С reverse=True они сортируются в обратном алфавитном порядке.
['apple', 'banana', 'cherry', 'date'] ['date', 'cherry', 'banana', 'apple']
Что такое функции-ключи (key) в сортировке Python?
Иногда сортировать нужно не по самим значениям, а по какому-то свойству каждого значения. Например, расставить слова по длине, а не по алфавиту.
Параметр key позволяет передать функцию, которая преобразует каждый элемент перед сравнением. Python применяет эту функцию к каждому элементу, а затем сортирует по полученным результатам. Сами элементы остаются прежними, меняется только порядок.
['pie', 'kiwi', 'banana', 'strawberry']
Здесь функцией-ключом служит len. Python вызывает len() для каждого слова и по этим длинам определяет порядок. В слове «pie» 3 буквы, в «kiwi» 4, и так далее.
В качестве ключа подойдёт любая функция. Типичный пример: сортировка без учёта регистра с помощью str.lower.
['Bob', 'CHARLIE', 'alice', 'dave'] ['alice', 'Bob', 'CHARLIE', 'dave']
Как сортировать с помощью lambda-функций
Встроенные функции вроде len и str.lower выручают не всегда. Когда нужна собственная логика сортировки, используют lambda: маленькую анонимную функцию, записанную в одну строку.
Lambda принимает элемент и возвращает значение, по которому нужно сортировать. Синтаксис: lambda item: expression.
[12, 23, 34, 45, 67, 89]
Функция lambda x: x % 10 берёт каждое число и возвращает его последнюю цифру (остаток от деления на 10). Затем Python сортирует по этим последним цифрам: 2, 3, 4, 5, 7, 9.
['zebra', 'apple', 'hello', 'mango']
['ant', 'bat', 'cat', 'dog', 'elephant']
Как сортировать словари и сложные данные
В реальных программах редко сортируют простые списки чисел. Гораздо чаще сортируют списки словарей: например, учеников по оценке или товары по цене.
Bob: 85 Diana: 88 Alice: 92 Charlie: 97
Charlie: 97 Alice: 92 Diana: 88 Bob: 85
Можно отсортировать и ключи или значения самого словаря. По умолчанию функция sorted() перебирает ключи словаря.
apple: $0.8 banana: $1.2 cherry: $3.5 date: $5.0 Traceback (most recent call last): File "<exec>", line 11, in <module> NameError: name 'f' is not defined
Что такое устойчивая сортировка и почему она важна?
Python использует алгоритм сортировки Timsort, и этот алгоритм устойчивый (стабильный). Это значит, что элементы, равные с точки зрения ключа сортировки, сохраняют исходный порядок.
На практике это очень важно. Если вы сортируете учеников по оценке и у двоих оценки одинаковые, они останутся в том же порядке, в каком были до сортировки.
Bob: 85 Diana: 85 Alice: 90 Charlie: 90
Практические упражнения
У вас есть список результатов теста. Выведите их отсортированными от меньшего к большему, а на следующей строке от большего к меньшему.
Используйте sorted(), чтобы исходный список остался без изменений.
Внимательно прочитайте код ниже. Что он выведет? Вспомните главное отличие sort() от sorted().
Напишите вывод в точности таким, каким его покажет программа.
Отсортируйте список слов по длине (сначала самые короткие). Если у двух слов одинаковая длина, они должны остаться в исходном порядке.
Выведите отсортированный список.
Код ниже пытается отсортировать имена по алфавиту, но имена с заглавной и со строчной буквы перемешиваются неправильно. Исправьте сортировку, чтобы имена шли в настоящем алфавитном порядке независимо от регистра.
Вывод должен быть таким: ['alice', 'Bob', 'Charlie', 'dave', 'Eve']
Отсортируйте список учеников по оценке, от высшей к низшей. Выведите имя и оценку каждого ученика на отдельной строке (имя, двоеточие, пробел и оценка) в формате: Name: Grade
Отсортируйте список товаров сначала по категории (по алфавиту), а внутри каждой категории по цене (сначала дешёвые).
Выведите каждый товар на отдельной строке (категория, название и цена) в формате: category: name - $price