Сортировка списков
Как сортировать списки Python с помощью sorted() и sort(), использовать параметр key, сортировать в обратном порядке и работать с объектами.
Сортировка списка — одна из наиболее частых операций в Python. Python предоставляет два встроенных инструмента для этого: функция sorted(), которая возвращает новый отсортированный список, не изменяя оригинал, и метод list.sort(), который сортирует список на месте. Оба принимают флаг reverse для сортировки по убыванию и параметр key для пользовательской логики сортировки.
Эта глава охватывает:
sorted()— сортировка любого итерируемого объекта в новый списокlist.sort()— сортировка списка на месте- Сортировка по возрастанию и убыванию
- Параметр
key— сортировка по длине, полю или любому пользовательскому критерию - Сортировка без учёта регистра
- Сортировка списков словарей и пользовательских объектов
- Многоключевая сортировка
operator.itemgetterкак эффективная альтернатива lambda
Для знакомства с основами списков смотрите главы Python Lists и List Methods.
Функция sorted()
sorted() принимает любой итерируемый объект (список, кортеж, строку, …) и возвращает новый отсортированный список. Исходный итерируемый объект остаётся неизменным.
Синтаксис:
sorted(iterable, *, key=None, reverse=False)iterable— последовательность для сортировкиkey— необязательная функция с одним аргументом, применяемая к каждому элементу перед сравнением (по умолчанию: сравнение элементов напрямую)reverse— установитеTrueдля сортировки по убыванию (по умолчанию:False)
Сортировка списка строк
Сортировка списка чисел
Числовые списки сортируются по величине, а не по строковому представлению (поэтому 10 не идёт раньше 9).
nums = [3, 1, 4, 1, 5, 9, 2, 6]
print(sorted(nums))
# [1, 1, 2, 3, 4, 5, 6, 9]Сортировка по убыванию с reverse=True
Передайте reverse=True, чтобы получить наибольшие значения первыми.
nums = [3, 1, 4, 1, 5, 9, 2, 6]
print(sorted(nums, reverse=True))
# [9, 6, 5, 4, 3, 2, 1, 1]Метод list.sort()
list.sort() переупорядочивает список на месте и всегда возвращает None. Используйте его, когда исходный порядок вам больше не нужен и вы хотите избежать накладных расходов памяти от второго списка.
Синтаксис:
list.sort(*, key=None, reverse=False)Параметры идентичны sorted().
Сортировка списка на месте
Сортировка по убыванию
sort() возвращает None — распространённая ошибка
Частая ошибка — присваивать результат sort() переменной:
fruits = ['banana', 'apple', 'cherry']
result = fruits.sort() # sort() modifies fruits, returns None
print(result) # None ← not the sorted list!
print(fruits) # ['apple', 'banana', 'cherry'] ← fruits was modifiedЕсли вам нужен и отсортированный результат, и исходный порядок, используйте вместо этого sorted().
sorted() vs list.sort() — когда что использовать
sorted() | list.sort() | |
|---|---|---|
| Возвращает | Новый отсортированный список | None |
| Исходный список | Не изменяется | Изменяется на месте |
| Работает с | Любым итерируемым объектом | Только со списками |
| Память | Использует дополнительную память | Без дополнительного списка |
Используйте sorted(), когда вам нужен исходный список без изменений, или при сортировке кортежа или другого итерируемого объекта.
Используйте list.sort(), когда у вас есть список, вы хотите отсортировать его на месте и важна эффективность использования памяти.
Сортировка с параметром key
Параметр key принимает вызываемый объект с одним аргументом. Python вызывает его один раз для каждого элемента и использует возвращённое значение для сравнений. Это позволяет избежать дублирования данных и делает сортировку гибкой.
Сортировка по длине строки
words = ['banana', 'apple', 'cherry', 'kiwi']
print(sorted(words, key=len))
# ['kiwi', 'apple', 'banana', 'cherry']len передаётся напрямую — lambda не нужна при использовании встроенной функции с одним аргументом.
Сортировка списка кортежей по конкретному полю
Lambda lambda x: x[1] извлекает второй элемент (число) из каждого кортежа, чтобы Python сравнивал числа, а не целые кортежи.
Сортировка списка словарей
students = [
{'name': 'Charlie', 'grade': 85},
{'name': 'Alice', 'grade': 92},
{'name': 'Bob', 'grade': 78},
]
by_grade = sorted(students, key=lambda s: s['grade'])
for s in by_grade:
print(s['name'], s['grade'])
# Bob 78
# Charlie 85
# Alice 92Для сортировки по убыванию (сначала наивысшая оценка) добавьте reverse=True:
by_grade_desc = sorted(students, key=lambda s: s['grade'], reverse=True)
for s in by_grade_desc:
print(s['name'], s['grade'])
# Alice 92
# Charlie 85
# Bob 78Сортировка без учёта регистра
По умолчанию сортировка в Python чувствительна к регистру: все заглавные буквы идут перед строчными, потому что имеют меньшие кодовые точки Unicode. Используйте key=str.lower для сортировки без учёта регистра.
words = ['Banana', 'apple', 'Cherry', 'date']
print(sorted(words)) # case-sensitive (uppercase first)
# ['Banana', 'Cherry', 'apple', 'date']
print(sorted(words, key=str.lower)) # case-insensitive
# ['apple', 'Banana', 'Cherry', 'date']Использование operator.itemgetter и operator.attrgetter
Модуль operator предоставляет более быстрые альтернативы lambda для распространённых шаблонов ключей.
operator.itemgetter — для последовательностей и словарей
import operator
fruits = [('apple', 10), ('banana', 5), ('cherry', 20)]
print(sorted(fruits, key=operator.itemgetter(1)))
# [('banana', 5), ('apple', 10), ('cherry', 20)]operator.itemgetter(1) эквивалентен lambda x: x[1], но реализован на C и работает быстрее на больших списках.
operator.attrgetter — для объектов
import operator
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __repr__(self):
return f'Student({self.name!r}, {self.grade})'
students = [Student('Charlie', 85), Student('Alice', 92), Student('Bob', 78)]
print(sorted(students, key=operator.attrgetter('grade')))
# [Student('Bob', 78), Student('Charlie', 85), Student('Alice', 92)]Многоключевая сортировка
Верните кортеж из функции key, чтобы сортировать по нескольким критериям. Python сравнивает кортежи поэлементно, поэтому при совпадении первого ключа используется второй.
# Sort by grade ascending, then by name alphabetically when grades tie
data = [('Alice', 85), ('Bob', 92), ('Charlie', 85), ('Dave', 78)]
result = sorted(data, key=lambda x: (x[1], x[0]))
print(result)
# [('Dave', 78), ('Alice', 85), ('Charlie', 85), ('Bob', 92)]У Alice и Charlie одинаковая оценка 85, поэтому они сортируются по алфавиту — Alice перед Charlie.
Стабильность сортировки
Сортировка Python стабильна: элементы, признанные равными, сохраняют исходный относительный порядок. Это означает, что можно отсортировать список по одному ключу, затем отсортировать результат по другому ключу, и порядок первой сортировки сохранится при совпадениях по второму ключу.
# Sort by grade, then (stably) by name — same result as the tuple key above
data = [('Alice', 85), ('Bob', 92), ('Charlie', 85), ('Dave', 78)]
step1 = sorted(data, key=lambda x: x[0]) # sort by name first
step2 = sorted(step1, key=lambda x: x[1]) # then sort by grade
print(step2)
# [('Dave', 78), ('Alice', 85), ('Charlie', 85), ('Bob', 92)]Этот приём — называемый преобразованием Шварца — иногда более читаем, чем составной ключ.
Заключение
sorted() и list.sort() в Python обеспечивают быструю и гибкую сортировку списков с минимальным количеством кода. Используйте sorted(), когда вам нужен новый список или вы сортируете не-списковый итерируемый объект; используйте list.sort(), когда хотите изменить список на месте. Параметр key справляется практически с любым критерием сортировки — от сортировки по длине или полю словаря до сравнений без учёта регистра. Для больших наборов данных предпочитайте operator.itemgetter или operator.attrgetter вместо lambda для лучшей производительности.
Дополнительное чтение:
- Python Lists — создание списков, индексация и срезы
- List Methods — полный справочник методов списков
- List Comprehension — лаконичное создание списков
- Loop Lists — итерация по спискам