Czy funkcja sortowana () w języku Python jest stabilna?

100

Dokumentacja nie gwarantuje. Czy jest jakieś inne miejsce, które jest udokumentowane?

Domyślam się, że może być stabilna, ponieważ metoda sortowania na listach jest gwarantowana jako stabilna (Uwagi 9 punkt: „Począwszy od Pythona 2.3, metoda sort () jest stabilna”), a sortowanie jest funkcjonalnie podobne. Jednak nie jestem w stanie znaleźć żadnego ostatecznego źródła, które by to mówiło.

Cel: muszę sortować na podstawie klucza podstawowego, a także klucza pomocniczego w przypadkach, gdy klucz podstawowy jest taki sam w obu rekordach. Jeśli gwarantujemy, że funkcja sortowania () jest stabilna, mogę posortować dane według klucza dodatkowego, a następnie posortować dane według klucza podstawowego i uzyskać wynik, którego potrzebuję.

PS: Aby uniknąć nieporozumień, używam stabilnego w znaczeniu „sort jest stabilny, jeśli gwarantuje, że nie zmieni się względnej kolejności elementów, które porównują równe sobie”.

sundar - Przywróć Monikę
źródło

Odpowiedzi:

130

Tak, intencją podręcznika jest rzeczywiście zagwarantowanie, że sortedjest stabilny i że używa dokładnie tego samego algorytmu, co sortmetoda. Zdaję sobie sprawę, że doktorzy nie są w 100% jasni co do tej tożsamości; doc patche są zawsze szczęśliwie akceptowane!

Alex Martelli
źródło
2
Zauważyłem, że jeśli sortuję krotki lub listy, za każdym razem, gdy „podstawowe” klucze sortowania są równe, sortowanie odbywa się według klucza „pomocniczego”. Na przykład sorted([(1, 2), (1, 1)])zwraca [(1, 1), (1, 2)]zamiast zwracać oryginalne dane wejściowe w tej samej kolejności / kolejności. Czy gwarancja stabilności nie powinna oznaczać, że powinna zwracać oryginalne [(1, 2), (1, 1)]dane wejściowe? W takim przypadku musisz być wyraźny i powiedziećsorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd
10
Czy nie tego oczekuje się w tym przypadku? Python będzie domyślnie porównywał krotki przez wszystkie elementy, a nie tylko pierwszy „podstawowy”. Jeśli chcesz sortować tylko według pierwszego elementu, możesz keyjawnie przekazać parametr.
Matias Grioni
2
@code_dredd jest to oczekiwane zachowanie. Celem stabilnego sortowania jest sortowanie przy użyciu „klucza sortowania”, ale dwa różne elementy, które mają ten sam klucz sortowania, będą w tej samej kolejności. Domyślnym kluczem sortowania krotki są wszystkie elementy krotki.
Guyarad
29

stabilne .

Przy okazji: czasami możesz zignorować wiedzę, czy sortowanie i sortowanie są stabilne, łącząc sortowanie wieloprzebiegowe z sortowaniem jednoprzebiegowym.

Na przykład, jeśli chcesz rodzaju obiektów na podstawie ich last_name, first_nameatrybutów, można to zrobić w jednym przebiegu:

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

korzystając z porównania krotek.

Ta odpowiedź, jak jest, obejmuje pierwotne pytanie. Więcej pytań związanych z sortowaniem można znaleźć w poradniku na temat sortowania w Pythonie .

tzot
źródło
5
Może to mieć niepożądany efekt, jeśli chcesz odwrócić sortowanie. Na przykład podczas sortowania według produktów możesz najpierw posortować według oceny (kolejność rosnąca), a następnie według ceny (również rosnąco). Jeśli to odwrócisz, chcesz posortować według oceny w porządku malejącym, ale według ceny w porządku rosnącym. To nie działa z tym rozwiązaniem.
Remco Wendt
2
@RemcoWendt: nie było wymagań co do tego, co opisujesz. W każdym razie rozważ key= lambda item: (-item.rating, item.price)lub podaj cmpzamiast keyargumentu. Jednak nadal nie jestem pewien, jaki jest cel Twojego komentarza.
tzot
1
Rzeczywiście, nie był to wymóg, ale chciałem zwrócić uwagę na tę subtelną różnicę, gdy inni ludzie to przeczytają i dokonają wyboru między twoim rozwiązaniem a używaniem funkcji stabilnego sortowania Pythona.
Remco Wendt
Widzę. Innymi słowy, sortowanie według par jest bardziej przejrzyste i dlatego preferowane, chyba że zależy Ci na wydajności. Wyobrażam sobie, że dwa stabilne rodzaje są nieco szybsze niż jeden sortowany po parach, chociaż różnica może być nieistotna -?
Sergey Orshanskiy
8
@tzot Chcę wspomnieć, że zawsze są takie wymagania dla stabilnego sortowania. Na przykład mam listę krotek (ocena, komentarz), komentarze są zapisywane w kolejności, w której powstały, a chcę sortować według stawki i zachować kolejność czasową, jednak nie zapisałem sygnatura czasowa na liście. Krótko mówiąc, chcę tylko posortować listę według stawki i zachować komentarz w tej samej kolejności.
wsysuper
4

Dokumentacja zmieniona w międzyczasie ( odpowiednie zobowiązanie ), a obecna dokumentacja sortedwyraźnie to gwarantuje:

Wbudowana sorted()funkcja gwarantuje stabilność. Sortowanie jest stabilne, jeśli gwarantuje, że nie zmieni względnej kolejności elementów, które porównują się równo - jest to pomocne przy sortowaniu w wielu zdaniach (na przykład sortowanie według działu, a następnie według poziomu wynagrodzenia).

Ta część dokumentacji została dodana do Pythona 2.7 i Pythona 3.4 (+), więc każda zgodna implementacja tej wersji językowej powinna mieć stabilną wersję sorted.

Zauważ, że w przypadku CPython list.sortbył stabilny od czasu Pythona 2.3

  • Tim Peters przepisał swoją list.sort()implementację - ta jest „stabilnym sortowaniem” (równe dane wejściowe pojawiają się w tej samej kolejności na wyjściu) i szybciej niż poprzednio.

Nie jestem pewien w 100% sorted, obecnie jest to proste użycie list.sort, ale nie sprawdzałem historii. Ale jest prawdopodobne, że był używany „zawsze” list.sort.

MSeifert
źródło
0

Dokumentacja „Co nowego” dla Pythona 2.4 skutecznie wskazuje, że sort () najpierw tworzy listę, a następnie wywołuje na niej sort (), zapewniając gwarancję, której potrzebujesz, chociaż nie ma jej w „oficjalnych” dokumentach. Jeśli naprawdę się martwisz, możesz po prostu sprawdzić źródło.

Peter Hansen
źródło
1
Czy możesz wskazać, gdzie jest to napisane? Mówi, że sort () "działa jak lokalna lista.sort ()" i "nowo utworzona kopia jest sortowana", ale nie widzę tego, że wewnętrznie używa sort ().
sundar - Przywróć Monikę
Utworzona „kopia” jest listą (otrzymujemy ją jako wartość zwracaną), a przed zwróceniem wywoływana jest funkcja .sort () z tej listy. CO BYŁO DO OKAZANIA. Nie, to nie jest niepodważalny dowód, ale dopóki Python nie będzie miał oficjalnego standardu, nie dostaniesz tego.
Peter Hansen
0

Dokument Python 3.6 dotyczący sortowania stwierdza teraz, że

Sortowanie gwarantuje stabilność

Ponadto w dokumencie tym znajduje się odsyłacz do stabilnego Timsort , który to stwierdza

Timsort jest standardowym algorytmem sortowania Pythona od wersji 2.3

Wolfgang Kuehn
źródło