Richtiger Weg, um ein OrderedDict mit seinem Konstruktor so zu initialisieren, dass die Reihenfolge der Anfangsdaten beibehalten wird?

124

Wie kann ein geordnetes Wörterbuch (OD) richtig initialisiert werden, damit die Reihenfolge der Anfangsdaten beibehalten wird?

from collections import OrderedDict

# Obviously wrong because regular dict loses order
d = OrderedDict({'b':2, 'a':1}) 

# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b',2), ('a', 1)])

# What about using a list comprehension, will 'd' preserve the order of 'l'
l = ['b', 'a', 'c', 'aa']
d = OrderedDict([(i,i) for i in l])

Frage:

  • Wird OrderedDictdie Reihenfolge einer Liste von Tupeln oder eines Tupels von Tupeln oder eines Tupels von Listen oder einer Liste von Listen usw. beibehalten, die zum Zeitpunkt der Initialisierung übergeben wurden (2. und 3. Beispiel oben)?

  • Wie kann man überprüfen, ob OrderedDicttatsächlich eine Bestellung aufrechterhalten wird? Da a dicteine unvorhersehbare Reihenfolge hat, was ist, wenn meine Testvektoren glücklicherweise dieselbe Anfangsreihenfolge haben wie die unvorhersehbare Reihenfolge eines Diktats? Wenn d = OrderedDict({'b':2, 'a':1})ich zum Beispiel nicht schreibe d = OrderedDict({'a':1, 'b':2}), kann ich fälschlicherweise den Schluss ziehen, dass die Reihenfolge erhalten bleibt. In diesem Fall habe ich herausgefunden, dass a dictalphabetisch geordnet ist, aber das ist möglicherweise nicht immer der Fall. Was ist ein zuverlässiger Weg, um anhand eines Gegenbeispiels zu überprüfen, ob eine Datenstruktur die Ordnung beibehält oder nicht, ohne wiederholt Testvektoren zu versuchen, bis einer bricht?

PS Ich lasse dies hier nur als Referenz : "Der OrderedDict-Konstruktor und die update () -Methode akzeptieren beide Schlüsselwortargumente, aber ihre Reihenfolge geht verloren, weil Pythons Funktionsaufrufsemantik die Schlüsselwortargumente mit einem regulären ungeordneten Wörterbuch übergibt."

PPS: Hoffentlich behält OrderedDict in Zukunft auch die Reihenfolge der kwargs bei (Beispiel 1): http://bugs.python.org/issue16991

klicken
quelle
9
Es ist vage ironisch, dass das Initialisieren eines OrderedDict mit einem (nicht leeren) Diktat das Falsche ist ... das sollte wohl zu einer Warnung führen, da es wahrscheinlich die Absicht des Benutzers verletzt.
smci
3
Nach Python3.6 OrderDict(b=2, a=1)ist auch ein richtiger Weg. Siehe PEP 468 .
IvanaGyro

Antworten:

90

Das OrderedDict behält jede Bestellung bei, auf die es Zugriff hat. Die einzige Möglichkeit, geordnete Daten zur Initialisierung an sie zu übergeben, besteht darin, eine Liste (oder allgemeiner eine iterierbare) von Schlüssel-Wert-Paaren zu übergeben, wie in Ihren letzten beiden Beispielen. Wie in der von Ihnen verlinkten Dokumentation angegeben, hat OrderedDict keinen Zugriff auf eine Reihenfolge, wenn Sie Schlüsselwortargumente oder ein Diktatargument übergeben, da dort eine Reihenfolge entfernt wird, bevor der OrderedDict-Konstruktor sie sieht.

Beachten Sie, dass die Verwendung eines Listenverständnisses in Ihrem letzten Beispiel nichts ändert. Es gibt keinen Unterschied zwischen OrderedDict([(i,i) for i in l])und OrderedDict([('b', 'b'), ('a', 'a'), ('c', 'c'), ('aa', 'aa')]). Das Listenverständnis wird ausgewertet und erstellt die Liste und wird übergeben; OrderedDict weiß nichts darüber, wie es erstellt wurde.

BrenBarn
quelle
74
# An OD is represented by a list of tuples, so would this work?
d = OrderedDict([('b', 2), ('a', 1)])

Ja, das wird funktionieren. Per Definition wird eine Liste immer so geordnet, wie sie dargestellt wird. Dies gilt auch für das Listenverständnis. Die generierte Liste entspricht der Bereitstellung der Daten (dh die Quelle aus einer Liste ist deterministisch, stammt aus einer setoder dictweniger).

Wie kann man überprüfen, ob OrderedDicttatsächlich eine Bestellung aufrechterhalten wird? Da ein Diktat eine unvorhersehbare Reihenfolge hat, was ist, wenn meine Testvektoren glücklicherweise dieselbe Anfangsreihenfolge haben wie die unvorhersehbare Reihenfolge eines Diktats? Wenn d = OrderedDict({'b':2, 'a':1})ich zum Beispiel nicht schreibe d = OrderedDict({'a':1, 'b':2}), kann ich fälschlicherweise den Schluss ziehen, dass die Reihenfolge erhalten bleibt. In diesem Fall habe ich herausgefunden, dass a dictalphabetisch geordnet ist, aber das ist möglicherweise nicht immer der Fall. Dies ist eine zuverlässige Methode, um anhand eines Zählerbeispiels zu überprüfen, ob eine Datenstruktur die Reihenfolge beibehält oder Testvektoren wiederholt versucht, bis eine Unterbrechung auftritt.

Sie behalten Ihre Quellliste mit 2 Tupeln als Referenz bei und verwenden diese als Testdaten für Ihre Testfälle, wenn Sie Komponententests durchführen. Durchlaufen Sie sie und stellen Sie sicher, dass die Reihenfolge eingehalten wird.

Metatoaster
quelle
Informationen zur Überprüfung der Reihenfolge: Wie stelle ich sicher, dass mein 2-Tupel die Reihenfolge des Diktats verletzt, wenn es nicht vorhersehbar ist? Dies ist eine allgemeine Frage zu jeder Datenstruktur. Vielleicht sollte ich sie von dieser Frage trennen.
Klicken Sie auf
1
Sie können etwas, das nicht deterministisch ist, nicht deterministisch brechen.
Metatoaster
1
Was ist der richtige Ansatz, um solche Dinge zu testen? Sie versuchen es einfach auf unbestimmte Zeit? Die Reihenfolge ist für Programmierer unvorhersehbar, aber da es sich um eine Hash-Map handelt, folgt sie einem Algorithmus und ein richtiger Test sollte versuchen, dem entgegenzuwirken.
Klicken Sie auf
2
Siehe __hash__. Speziell über den strTyp.
Metatoaster
Per Definition wird eine Liste immer so geordnet, wie sie dargestellt wird. Dies war eine wichtige Aussage für mich. Ich habe mich entschieden, einfach eine Liste mit 2 Tupeln für mein Basic zu verwenden, OrderedDictdamit ich nicht den Aufwand habe, eine Liste in eine zu konvertieren OrderedDict. Ich durchlaufe die Elemente einfach wie eine Liste anstelle eines Wörterbuchs.
Bobort