Ist die sorted () - Funktion von Python garantiert stabil?

95

Die Dokumentation garantiert das nicht. Gibt es einen anderen Ort, an dem dies dokumentiert ist?

Ich vermute, es könnte stabil sein, da die Sortiermethode in Listen garantiert stabil ist (Anmerkungen 9. Punkt: "Ab Python 2.3 ist die sort () -Methode garantiert stabil") und sortiert ist funktional ähnlich. Ich kann jedoch keine endgültige Quelle finden, die dies sagt.

Zweck: Ich muss nach einem Primärschlüssel und auch nach einem Sekundärschlüssel sortieren, wenn der Primärschlüssel in beiden Datensätzen gleich ist. Wenn sorted () garantiert stabil ist, kann ich nach dem Sekundärschlüssel sortieren, dann nach dem Primärschlüssel sortieren und das gewünschte Ergebnis erhalten.

PS: Um Verwirrung zu vermeiden, verwende ich Stable im Sinne von "Eine Sortierung ist stabil, wenn sie garantiert, dass die relative Reihenfolge von Elementen, die gleich sind, nicht geändert wird".

Sundar - Monica wieder einsetzen
quelle

Antworten:

126

Ja, das Handbuch soll in der Tat sicherstellen, dass sortedes stabil ist und dass es genau den gleichen Algorithmus wie die sortMethode verwendet. Mir ist klar, dass die Dokumente über diese Identität nicht 100% klar sind. Doc Patches werden immer gerne angenommen!

Alex Martelli
quelle
2
Ich habe festgestellt, dass beim Sortieren von Tupeln oder Listen immer dann, wenn die "primären" Sortierschlüssel gleich sind, die Sortierung nach dem "sekundären" Schlüssel erfolgt. Gibt beispielsweise sorted([(1, 2), (1, 1)])zurück, [(1, 1), (1, 2)]anstatt die ursprüngliche Eingabe in derselben Reihenfolge / Reihenfolge zurückzugeben. Sollte die Stabilitätsgarantie nicht bedeuten, dass die ursprüngliche [(1, 2), (1, 1)]Eingabe zurückgegeben wird? In diesem Fall müssen Sie explizit sein und sagensorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd
10
Ist das nicht das, was in diesem Fall erwartet wird? Python vergleicht standardmäßig Tupel mit allen Elementen, nicht nur mit dem ersten "primären". Wenn Sie nur nach dem ersten Element sortieren möchten, können Sie den keyParameter explizit übergeben.
Matias Grioni
2
@code_dredd Dies ist das erwartete Verhalten. Der Punkt der stabilen Sortierung ist das Sortieren mit einem "Sortierschlüssel", aber zwei verschiedene Elemente mit demselben Sortierschlüssel befinden sich in derselben Reihenfolge. Der Standard-Sortierschlüssel für ein Tupel sind alle Elemente des Tupels.
Guyarad
27

Sie sind stabil .

Übrigens: Sie können manchmal ignorieren, ob Sortierung und Sortierung stabil sind, indem Sie eine Sortierung mit mehreren Durchgängen in einer Sortierung mit einem Durchgang kombinieren.

Zum Beispiel auf ihre Objekte basiert , wenn Sie sortieren möchten last_name, first_nameAttribute, können Sie es in einem Durchgang tun:

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

Tupelvergleich nutzen.

Diese Antwort deckt die ursprüngliche Frage ab. Für weitere Fragen zum Sortieren gibt es die Python-Sortieranleitung .

tzot
quelle
4
Dies kann unerwünschte Auswirkungen haben, wenn Sie die Sortierung umkehren möchten. Wenn Sie beispielsweise nach Produkten sortieren, möchten Sie möglicherweise zuerst nach Bewertung (aufsteigende Reihenfolge) und dann nach Preis (auch aufsteigend) sortieren. Wenn Sie dies umkehren, möchten Sie nach Bewertung in absteigender Reihenfolge, aber nach Preis in aufsteigender Reihenfolge sortieren. Dies funktioniert mit dieser Lösung nicht.
Remco Wendt
2
@ RemcoWendt: Es gab keine Anforderung für das, was Sie beschreiben. Betrachten key= lambda item: (-item.rating, item.price)oder liefern Sie in jedem Fall cmpein keyArgument anstelle eines Arguments. Ich bin mir jedoch immer noch nicht sicher, welchen Zweck Ihr Kommentar hat.
Zot
1
In der Tat war dies keine Voraussetzung, aber ich wollte auf diesen subtilen Unterschied hinweisen, wenn andere Leute dies lesen und zwischen Ihrer Lösung oder der Verwendung der stabilen Sortierfunktion von Python wählen.
Remco Wendt
Aha. Mit anderen Worten, die Sortierung nach Paaren ist klarer und daher vorzuziehen, es sei denn, Sie legen Wert auf Leistung. Ich würde mir vorstellen, dass zwei stabile Sorten etwas schneller sind als eine paarweise, obwohl der Unterschied vernachlässigbar sein kann -?
osa
8
@tzot Ich möchte erwähnen, dass es immer solche Anforderungen für eine stabile Sortierung gibt. Zum Beispiel habe ich eine Liste mit Tupeln (Rate, Kommentar), die Kommentare werden in der Reihenfolge gespeichert, in der sie erstellt wurden, und ich möchte nach der Rate sortieren und die Zeitreihenfolge beibehalten, die ich jedoch nicht gespeichert habe Zeitstempel in der Liste. Um es kurz zu sagen, ich möchte die Liste nur nach Rate sortieren und den Kommentar in derselben Reihenfolge halten.
wsysuper
3

Die in der Zwischenzeit geänderte Dokumentation ( relevantes Commit ) und die aktuelle Dokumentation von sortedgarantiert dies ausdrücklich:

Die eingebaute sorted()Funktion ist garantiert stabil. Eine Sortierung ist stabil, wenn sie garantiert, dass die relative Reihenfolge der Elemente, die gleich sind, nicht geändert wird. Dies ist hilfreich, um in mehreren Durchgängen zu sortieren (z. B. nach Abteilung und dann nach Gehaltsstufe sortieren).

Dieser Teil der Dokumentation wurde hinzugefügt , um Python 2.7 und Python 3.4 (+) so jede kompatible Implementierung dieser Sprachversion sollte haben eine stabilesorted .

Beachten Sie, dass für CPython das list.sortseit Python 2.3 stabil ist

  • Tim Peters hat seine list.sort()Implementierung neu geschrieben - dies ist eine "stabile Sortierung" (gleiche Eingaben erscheinen in der Ausgabe in derselben Reihenfolge) und schneller als zuvor.

Ich bin mir nicht 100% sicher sorted, heutzutage wird es einfach verwendet list.sort, aber ich habe den Verlauf nicht darauf überprüft. Aber es ist wahrscheinlich, dass es "immer" verwendet wird list.sort.

MSeifert
quelle
0

In den "Was ist neu" -Dokumenten für Python 2.4 wird effektiv darauf hingewiesen, dass sorted () zuerst eine Liste erstellt und dann sort () aufruft, um Ihnen die Garantie zu geben, die Sie benötigen, jedoch nicht in den "offiziellen" Dokumenten. Sie können auch einfach die Quelle überprüfen, wenn Sie wirklich besorgt sind.

Peter Hansen
quelle
1
Könnten Sie darauf hinweisen, wo es so steht? Es heißt sorted () "funktioniert wie die In-Place-Liste.sort ()" und "eine neu erstellte Kopie wird sortiert", aber ich sehe nicht, dass es sort () intern verwendet.
Sundar - Stellen Sie Monica
Die "Kopie", die gebildet wird, ist eine Liste (das erhalten Sie als Rückgabewert), und .sort () wird vor der Rückgabe in dieser Liste aufgerufen. QED. Nein, es ist kein unangreifbarer Beweis, aber bis Python einen offiziellen Standard hat, werden Sie das nicht bekommen.
Peter Hansen
0

Das Python 3.6-Dokument zum Sortieren besagt dies jetzt

Sorten sind garantiert stabil

Darüber hinaus gibt es in diesem Dokument einen Link zum Stall Timsort , der besagt, dass

Timsort ist seit Version 2.3 Pythons Standard-Sortieralgorithmus

Wolfgang Kühn
quelle