Чи гарантована стабільність функції sorted () python?


96

Документація не гарантує , що. Чи є інше місце, де це задокументовано?

Я припускаю, що він може бути стабільним, оскільки метод сортування у списках гарантовано стабільний (Примітки 9-й пункт: "Починаючи з Python 2.3, метод sort () гарантовано буде стабільним"), і сортування функціонально подібне. Однак я не можу знайти жодного остаточного джерела, яке б так говорило.

Призначення: Мені потрібно сортувати на основі первинного ключа, а також вторинного ключа у випадках, коли первинний ключ рівний в обох записах. Якщо sorted () гарантовано стабільний, я можу відсортувати за вторинним ключем, потім відсортувати за первинним ключем і отримати потрібний результат.

PS: Щоб уникнути плутанини, я використовую стабільний у значенні "сортування є стабільним, якщо воно гарантує не змінювати відносний порядок елементів, які порівнюють рівні".

Відповіді:


127

Так, метою посібника є справді гарантувати sortedстабільність і справді те, що в ньому використовується точно такий самий алгоритм, як і sortметод. Я усвідомлюю, що документи не є на 100% зрозумілими щодо цієї особистості; патчі для документа завжди раді прийняти!


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

10
Хіба це не те, що очікується у цій справі? Python збирається порівнювати кортежі за допомогою всіх елементів за замовчуванням, а не лише першого "основного". Якщо ви хочете сортувати лише за першим елементом, ви можете передати keyпараметр явно.
Matias Grioni

2
@code_dredd це очікувана поведінка. Точка стабільного сортування - це сортування за допомогою "ключа сортування", але два різні елементи, що мають однаковий ключ сортування, будуть в однаковому порядку. Ключем сортування за замовчуванням для кортежу є всі елементи кортежу.
гаярад

27

Вони стабільні .

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

Наприклад, якщо ви хочете , щоб впорядкувати об'єкти на основі їх last_name, first_nameатрибутів, ви можете зробити це за один прохід:

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

скориставшись порівнянням кортежів.

Ця відповідь, як є, охоплює вихідне питання. Для подальших питань, пов’язаних із сортуванням, є інструкція з сортування Python .


4
Це може мати небажаний ефект, якщо ви хочете змінити порядок сортування. Наприклад, під час сортування за продуктами, ви можете спершу відсортувати за рейтингом (за зростанням), а потім за ціною (також за зростанням). Якщо ви відміните це, ви хочете відсортувати за рейтингом у порядку зменшення, але за ціною за зростанням. Це не працює з цим рішенням.
Ремко Вендт

2
@RemcoWendt: не було вимог до того, що ви описуєте. У будь-якому випадку, розгляньте key= lambda item: (-item.rating, item.price)або надайте cmpзамість keyаргументу. Однак я все ще не впевнений у меті Вашого коментаря.
tzot

1
Дійсно, це не була вимога, але я хотів вказати на цю незначну різницю, коли інші люди читають це і роблять вибір між вашим рішенням або використанням стабільної функції сортування Python.
Ремко Вендт

Я бачу. Іншими словами, сортування за парами є чіткішим і, отже, кращим, якщо ви не дбаєте про ефективність. Я уявляю, що два стабільні сорти дещо швидші за сортування по парах, хоча різниця може бути незначною -?
Сергій Оршанський

8
@tzot Я хочу зазначити, завжди існують такі вимоги до стабільного сортування. Наприклад, у мене є список кортежу (оцінка, коментар), коментарі зберігаються в порядку, коли вони були зроблені, і я хочу відсортувати за курсом і зберегти часовий порядок, однак я не зберег позначка часу у списку. Якщо сказати коротко, я просто хочу відсортувати список за курсом і залишити коментар у тому самому порядку.
wsysuper

3

Документація тим часом змінилася ( відповідна комісія ), і поточна документація 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

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

0

У документі Python 3.6 про сортування тепер зазначено, що

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

Крім того, у цьому документі є посилання на стабільний Timsort , де зазначено

Тимсорт є стандартним алгоритмом сортування Python з версії 2.3

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.