Всё о сортировке в Python: исчерпывающий гайд
Сортировка в Python выполняется с помощью sorted() и list.sort(). Разбираем на примерах, как это работает.
822К открытий1М показов
Сортировка в Python выполняется функцией sorted()
, если это итерируемые объекты, и методом list.sort()
, если это список. Рассмотрим подробнее, как это работало в старых версиях и как работает сейчас.
Примечание Вы читаете улучшенную версию некогда выпущенной нами статьи.
Основы сортировки
Так как отсортировать список Python? Для сортировки по возрастанию достаточно вызвать функцию сортировки Python sorted()
, которая вернёт новый отсортированный список:
Для сортировки списка Python также можно использовать метод списков list.sort()
, который изменяет исходный список (и возвращает None
во избежание путаницы). Обычно Python sort list не так удобен, как использование sorted()
, но если вам не нужен исходный список, то так будет немного эффективнее:
Прим.перев. В Python вернуть None
и не вернуть ничего — одно и то же.
Ещё одно отличие заключается в том, что метод list.sort()
определён только для списков, в то время как функция sorted Python работает со всеми итерируемыми объектами. Грубо говоря, функция sort Python сортирует список и сохраняет его в отсортированном виде, в то время как функция sorted Питон создаёт новый отсортированный список без изменения исходного.
Прим.перев. При итерировании по словарю Python возвращает его ключи. Если вам нужны их значения или пары «ключ-значение», используйте методы dict.values()
и dict.items()
соответственно.
Рассмотрим основные функции сортировки Python.
Функции-ключи
С версии Python 2.4 у list.sort()
и sorted()
появился параметр key
для указания функции, которая будет вызываться на каждом элементе до сравнения. Вот регистронезависимое сравнение строк:
Значение key
должно быть функцией, принимающей один аргумент и возвращающей ключ для сортировки. Работает быстро, потому что функция-ключ вызывается один раз для каждого элемента.
Часто можно встретить код, где сложный объект сортируется по одному из его индексов. Например:
Тот же метод работает для объектов с именованными атрибутами:
Функции модуля operator
Показанные выше примеры функций-ключей встречаются настолько часто, что Python предлагает удобные функции, чтобы сделать всё проще и быстрее. Модуль operator содержит функции itemgetter()
, attrgetter()
и, начиная с Python 2.6, methodcaller()
. С ними всё ещё проще:
Функции operator дают возможность использовать множественные уровни сортировки массива Python. Отсортируем учеников сначала по оценке, а затем по возрасту:
Используем функцию methodcaller()
для сортировки учеников по взвешенной оценке:
Сортировка по возрастанию и сортировка по убыванию в Python
list.sort()
и sorted()
есть параметр reverse
, принимающий boolean-значение. Он нужен для обозначения сортировки по убыванию. Отсортируем учеников по убыванию возраста:
Стабильность сортировки и сложные сортировки в Python
Начиная с версии Python 2.2, сортировки гарантированно стабильны: если у нескольких записей есть одинаковые ключи, их порядок останется прежним. Пример:
Обратите внимание, что две записи с 'blue'
сохранили начальный порядок. Это свойство позволяет составлять сложные сортировки путём постепенных сортировок. Далее мы сортируем данные учеников сначала по возрасту в порядке возрастания, а затем по оценкам в убывающем порядке, чтобы получить данные, отсортированные в первую очередь по оценке и во вторую — по возрасту:
Алгоритмы сортировки Python вроде Timsort проводят множественные сортировки так эффективно, потому что может извлечь пользу из любого порядка, уже присутствующего в наборе данных.
Декорируем-сортируем-раздекорируем
- Сначала исходный список пополняется новыми значениями, контролирующими порядок сортировки.
- Затем новый список сортируется.
- После этого добавленные значения убираются, и в итоге остаётся отсортированный список, содержащий только исходные элементы.
Вот так можно отсортировать данные учеников по оценке:
Это работает из-за того, что кортежи сравниваются лексикографически, сравниваются первые элементы, а если они совпадают, то сравниваются вторые и так далее.
Не всегда обязательно включать индекс в декорируемый список, но у него есть преимущества:
- Сортировка стабильна — если у двух элементов одинаковый ключ, то их порядок не изменится.
- У исходных элементов не обязательно должна быть возможность сравнения, так как порядок декорированных кортежей будет определяться максимум по первым двум элементам. Например, исходный список может содержать комплексные числа, которые нельзя сравнивать напрямую.
Ещё эта идиома называется преобразованием Шварца в честь Рэндела Шварца, который популяризировал её среди Perl-программистов.
Для больших списков и версий Python ниже 2.4, «декорируем-сортируем-раздекорируем» будет оптимальным способом сортировки. Для версий 2.4+ ту же функциональность предоставляют функции-ключи.
Использование параметра cmp
Все версии Python 2.x поддерживали параметр cmp
для обработки пользовательских функций сравнения. В Python 3.0 от этого параметра полностью избавились. В Python 2.x в sort()
можно было передать функцию, которая использовалась бы для сравнения элементов. Она должна принимать два аргумента и возвращать отрицательное значение для случая «меньше чем», положительное — для «больше чем» и ноль, если они равны:
Можно сравнивать в обратном порядке:
При портировании кода с версии 2.x на 3.x может возникнуть ситуация, когда нужно преобразовать пользовательскую функцию для сравнения в функцию-ключ. Следующая обёртка упрощает эту задачу по Python:
Чтобы произвести преобразование, оберните старую функцию:
В Python 2.7 функция cmp_to_key()
была добавлена в модуль functools.
Поддержание порядка сортировки
В стандартной библиотеке Python нет модулей, аналогичных типам данных C++ вроде set
и map
. Python делегирует эти задачи сторонним библиотекам, доступным в Python Package Index: они используют различные методы для сохранения типов list
, dict
и set
в отсортированном порядке. Поддержание порядка с помощью специальной структуры данных может помочь избежать очень медленного поведения (квадратичного времени выполнения) при наивном подходе с редактированием и постоянной пересортировкой данных. Вот некоторые из модулей, реализующих эти типы данных:
- SortedContainers — реализация сортированных типов
list
,dict
иset
на чистом Python, по скорости не уступает реализациям на C. Тестирование включает 100% покрытие кода и многие часы стресс-тестирования. В документации можно найти полный справочник по API, сравнение производительности и руководства по внесению своего вклада. - rbtree — быстрая реализация на C для типов
dict
иset
. Реализация использует структуру данных, известную как красно-чёрное дерево. - treap — сортированный
dict
. В реализации используется Декартово дерево, а производительность улучшена с помощью Cython. - bintrees — несколько реализаций типов
dict
иset
на основе деревьев на C. Самые быстрые основаны на АВЛ и красно-чёрных деревьях. Расширяет общепринятый API для предоставления операций множеств для словарей. - banyan — быстрая реализация
dict
иset
на C. - skiplistcollections — реализация на чистом Python, основанная на списках с пропусками, предлагает ограниченный API для типов
dict
иset
. - blist — предоставляет сортированные типы
list
,dict
иset
, основанные на типе данных «blist», реализация на Б-деревьях. Написано на Python и C.
Прочее
Для сортировки с учётом языка используйте locale.strxfrm()
в качестве ключевой функции или locale.strcoll()
в качестве функции сравнения. Параметр reverse
всё ещё сохраняет стабильность сортировки. Этот эффект можно сымитировать без параметра, использовав встроенную функцию reversed()
дважды:
Чтобы создать стандартный порядок сортировки для класса, просто добавьте реализацию соответствующих методов сравнения:
Для типов, сравнение которых работает обычным образом, рекомендуется определять все 6 операторов. Декоратор классов functools.total_ordering
упрощает их реализацию. Функциям-ключам не нужен доступ к внутренним данным сортируемых объектов. Они также могут осуществлять доступ к внешним ресурсам. Например, если оценки ученика хранятся в словаре, их можно использовать для сортировки отдельного списка с именами учеников:
Надеемся, теория по Python list sort и соответствующие задачи по Питону с разбором были для вас полезны. Вас также может заинтересовать статьи:
822К открытий1М показов