Гарантируется ли стабильность функции sorted () Python?


100

Документация не гарантирует , что. Есть ли другое место, где это задокументировано?

Я предполагаю, что он может быть стабильным, так как метод sort в списках гарантированно стабилен (примечания 9 пункт: «Начиная с Python 2.3, метод sort () гарантированно стабилен»), а sorted функционально аналогичен. Однако я не могу найти какой-либо исчерпывающий источник, в котором говорится об этом.

Цель: мне нужно выполнить сортировку на основе первичного ключа, а также вторичного ключа в тех случаях, когда первичный ключ одинаков в обеих записях. Если sorted () гарантированно будет стабильным, я могу отсортировать по вторичному ключу, затем отсортировать по первичному ключу и получить нужный мне результат.

PS: Чтобы избежать путаницы, я использую стабильный в смысле «сортировка стабильна, если она гарантирует, что не изменит относительный порядок элементов, которые сравниваются равными».

Ответы:


130

Да, цель руководства действительно состоит в том, чтобы гарантировать sortedстабильность и использование того же алгоритма, что и sortметод. Я действительно понимаю, что документы не на 100% ясны об этой личности; doc патчи всегда с радостью принимаются!


2
Я обнаружил, что если я сортирую кортежи или списки, когда «первичные» ключи сортировки равны, это заканчивается сортировкой по «вторичному» ключу. Например, sorted([(1, 2), (1, 1)])возвращает [(1, 1), (1, 2)]вместо исходного ввода в той же последовательности / порядке. Разве гарантия стабильности не должна означать, что он должен возвращать исходный [(1, 2), (1, 1)]ввод? В этом случае вы должны быть явным и сказатьsorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd 01

10
Разве в этом случае не этого? Python по умолчанию будет сравнивать кортежи по всем элементам, а не только по первому «первичному». Если вы хотите выполнить сортировку только по первому элементу, вы можете keyявно передать параметр.
Матиас Гриони

2
@code_dredd это ожидаемое поведение. Суть стабильной сортировки - это сортировка с использованием «ключа сортировки», но два разных элемента с одинаковым ключом сортировки будут располагаться в одном порядке. Ключ сортировки по умолчанию для кортежа - это все элементы кортежа.
Guyarad 05

29

Они стабильны .

Кстати: иногда вы можете игнорировать знание того, стабильны ли сортировка и сортировка, комбинируя многопроходную сортировку с однопроходной.

Например, если вы хотите , чтобы отсортировать объекты на основе их last_name, first_nameатрибутов, вы можете сделать это за один проход:

sorted_list= sorted(
    your_sequence_of_items,
    key= lambda item: (item.last_name, item.first_name))

пользуясь преимуществом сравнения кортежей.

Этот ответ как есть охватывает исходный вопрос. Для дальнейших вопросов, связанных с сортировкой, есть руководство по сортировке Python .


5
Это может иметь нежелательный эффект, если вы хотите отменить сортировку. Например, при сортировке продуктов вы можете сначала выполнить сортировку по рейтингу (в порядке возрастания), а затем по цене (также по возрастанию). Если вы отмените это, вы хотите отсортировать по рейтингу в порядке убывания, но по цене в порядке возрастания. Это не работает с этим решением.
Remco Wendt

2
@RemcoWendt: не было требований к тому, что вы описываете. В любом случае, рассмотрите key= lambda item: (-item.rating, item.price)или предоставьте cmpвместо keyаргумента. Однако я до сих пор не уверен в цели вашего комментария.
tzot 08

1
На самом деле это не было требованием, но я хотел указать на эту тонкую разницу, когда другие люди читают это и делают выбор между вашим решением или использованием стабильной функции сортировки Python.
Remco Wendt,

Понимаю. Другими словами, сортировка по парам более понятна и поэтому предпочтительнее, если вы не заботитесь о производительности. Я полагаю, что две стабильные сортировки несколько быстрее, чем одна сортировка по парам, хотя разница может быть незначительной -?
Сергей Оршанский

8
@tzot Хочу отметить, такие требования для стабильной сортировки всегда есть. Например, у меня есть список кортежей (рейтинг, комментарий), комментарии сохраняются в том порядке, в котором они были сделаны, и я хочу отсортировать по скорости и сохранить временной порядок, однако я не сохранял отметка времени в списке. Короче говоря, я просто хочу отсортировать список по рейтингу и оставить комментарии в том же порядке.
wsysuper

4

Тем временем документация была изменена ( соответствующий коммит ), и текущая документация sortedявно гарантирует это:

sorted()Гарантированная стабильность встроенной функции. Сортировка является стабильной, если она гарантирует не изменить относительный порядок сравниваемых элементов - это полезно для сортировки за несколько проходов (например, сортировка по отделам, а затем по разряду зарплаты).

Эта часть документации была добавлена ​​в Python 2.7 и Python 3.4 (+), поэтому любая совместимая реализация этой языковой версии должна иметь стабильнуюsorted .

Обратите внимание, что для CPython list.sortон был стабильным с Python 2.3.

  • Тим Петерс переписал свою list.sort()реализацию - это «стабильная сортировка» (одинаковые входные данные появляются в одном и том же порядке на выходе) и быстрее, чем раньше.

Я не уверен на 100% sorted, в настоящее время он прост в использовании list.sort, но я не проверял историю на предмет этого. Но вполне вероятно, что его «всегда» использовали list.sort.


0

Документы «Что нового» для Python 2.4 фактически указывают на то, что sorted () сначала создает список, а затем вызывает для него sort (), предоставляя вам необходимую гарантию, хотя и не в «официальных» документах. Вы также можете просто проверить источник, если вас действительно беспокоит.


1
Не могли бы вы указать, где это сказано? В нем говорится, что sorted () «работает как in-place list.sort ()» и «вновь сформированная копия сортируется», но я не вижу, чтобы он говорил, что он внутренне использует sort ().
sundar - Reinstate Monica

Сформированная «копия» представляет собой список (это то, что вы получаете как возвращаемое значение), и .sort () вызывается в этом списке перед возвратом. QED. Нет, это не неопровержимое доказательство, но пока у Python не будет официального стандарта, вы его не получите.
Питер Хансен

0

В документе Python 3.6 о сортировке теперь говорится, что

Сорта гарантированно стабильны

Кроме того, в этом документе есть ссылка на стабильную версию Timsort , в которой говорится, что

Timsort - стандартный алгоритм сортировки Python с версии 2.3.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.