2014-05-11 6 views
5

Ich versuche, Elemente aus einem Wörterbuch zu löschen, wenn der Wert des Schlüssels unter einem bestimmten Schwellenwert liegt. Für ein einfaches Beispiel zu dem, was ich meine:Löschen von Elementen aus einem Wörterbuch mit einer for-Schleife

my_dict = {'blue': 1, 'red': 2, 'yellow': 3, 'green': 4} 

for color in my_dict: 
    threshold_value = 3 
    if my_dict[color] < threshold_value: 
     del my_dict[color] 

print(my_dict) 

Nun bekomme ich einen RuntimeError: dictionary changed size during iteration Fehler. Keine großen Überraschungen dort. Der Grund, warum ich diese Frage bin Entsendung ist:

  1. Finde heraus, ob es eine elegante Lösung ist, die nicht erfordert ein neues Wörterbuch zu schaffen (das gilt nur die Schlüssel mit Werten> = Schwelle).

  2. Versuchen Sie, Pythons Begründung hier zu verstehen. Die Art, wie ich es mir vorlese ist: "gehe zum ersten Schlüssel. Ist der Wert dieses Schlüssels < x? Wenn ja - ziehe diesen Schlüssel: value item und fahre mit der nächsten Taste im Wörterbuch fort, wenn nein - fahre fort nächster Schlüssel ohne etwas zu tun ". Mit anderen Worten, was historisch mit früheren Schlüsseln geschah, sollte nicht beeinflussen, wohin ich als nächstes gehe. Ich freue mich auf die nächsten Punkte, unabhängig von der Vergangenheit. Ich weiß, es ist lustig (manche sagen vielleicht blöd, das gebe ich dir), aber was ist Pythons "Art zu denken" über diese Schleife? Warum funktioniert es nicht? Wie würde Python es sich selbst vorlesen? Ich versuche nur, ein besseres Verständnis für die Sprache zu bekommen ...

Antwort

10

Aufgrund der Tatsache, dass Python Wörterbücher als Hash-Tabellen implementiert sind, sollten Sie sich nicht auf sie verlassen, um jede Art von einer Bestellung haben. Die Tastenreihenfolge kann sich unvorhersehbar ändern (aber nur nach dem Einfügen oder Entfernen eines Schlüssels). Daher ist es unmöglich, den nächsten Schlüssel vorherzusagen. Python wirft die RuntimeError, um sicher zu sein, und um zu verhindern, dass Leute in unerwartete Ergebnisse geraten.

Python 2 dict.items Methode gibt eine kopieren von Schlüssel-Wert-Paare, so dass Sie sicher über sie iterieren und löschen können Werte, die Sie mit den Tasten müssen nicht, wie @wim in Kommentaren vorgeschlagen. Beispiel:

for k, v in my_dict.items(): 
    if v < threshold_value: 
     del my_dict[k] 

Allerdings gibt Python 3 ist dict.items eine view object, der alle Änderungen in das Wörterbuch gemacht widerspiegelt. Das ist der Grund, warum die obige Lösung nur in Python 2 funktioniert. Sie können my_dict.items() in list (tuple usw.) konvertieren, um es Python 3-kompatibel zu machen.

Eine andere Möglichkeit, das Problem zu nähern, ist Schlüssel, die Sie auswählen möchten löschen und dann löschen

keys = [k for k, v in my_dict.items() if v < threshold_value] 
for x in keys: 
    del my_dict[x] 

Das in beiden Werken Python 2 und Python 3.

2

Wörterbücher ungeordnet sind. Durch das Löschen eines Schlüssels kann niemand sagen, was der nächste Schlüssel ist. So dass Python im Allgemeinen nicht erlaubt, Schlüssel aus einem Wörterbuch hinzuzufügen oder zu entfernen, wird darüber iteriert.

Erstellen Sie einfach ein neues:

my_dict = {"blue":1,"red":2,"yellow":3,"green":4} 
new_dict = {k:v for k,v in my_dict.iteritems() if v >= threshold_value} 
+0

wie ich im OP gesagt habe, will ich kein neues Diktat erstellen. – Optimesh

+0

Sie haben nach einem eleganten Weg gefragt. Aber Sie können programmieren, was Sie wollen. – Daniel

0

Ich denke, dass eine Sammlung zu modifizieren, während über sie iterieren eine harte Sache ist richtig zu implementieren zu tun. Betrachten Sie folgendes Beispiel:

>>> list = [1, 2, 3, 4, 5, 6] 
>>> for ii in range(len(list)): 
    print list[ii]; 
    if list[ii] == 3: 
    del list[ii]  
1 
2 
3 
5 
6 

Beachten Sie, dass in diesem Beispiel 4 insgesamt weggelassen wurde.Es ist sehr ähnlich in Wörterbüchern, das Löschen/Hinzufügen von Einträgen könnte interne Strukturen ungültig machen, die die Reihenfolge der Iteration definieren (zum Beispiel haben Sie genug Einträge gelöscht, so dass sich die Hash-Map-Bucket-Größe änderte).

Um Ihren Fall zu lösen --- erstellen Sie einfach ein neues Wörterbuch und kopieren Sie die Artikel dort. Wie zu

Verwandte Themen