Ist es legitim, Elemente aus einem Wörterbuch in Python zu löschen, während Sie darüber iterieren?
Beispielsweise:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
Die Idee ist, Elemente, die eine bestimmte Bedingung nicht erfüllen, aus dem Wörterbuch zu entfernen, anstatt ein neues Wörterbuch zu erstellen, das eine Teilmenge des Wörterbuchs ist, über das iteriert wird.
Ist das eine gute Lösung? Gibt es elegantere / effizientere Wege?
scripting
dictionary
python
Trilarion
quelle
quelle
Antworten:
BEARBEITEN:
Diese Antwort funktioniert nicht für Python3 und gibt eine
RuntimeError
.Dies liegt daran, dass
mydict.keys()
ein Iterator keine Liste zurückgibt. Wie in den Kommentaren erwähnt, konvertieren Sie einfachmydict.keys()
in eine Liste vonlist(mydict.keys())
und es sollte funktionieren.Ein einfacher Test in der Konsole zeigt, dass Sie ein Wörterbuch nicht ändern können, während Sie es durchlaufen:
Wie in der Antwort von delnan angegeben, verursacht das Löschen von Einträgen Probleme, wenn der Iterator versucht, zum nächsten Eintrag überzugehen. Verwenden Sie stattdessen die
keys()
Methode, um eine Liste der Schlüssel abzurufen und damit zu arbeiten:Wenn Sie basierend auf dem Elementwert löschen müssen, verwenden Sie
items()
stattdessen die folgende Methode:quelle
for k, v in list(mydict.items()):
in Python 3 gut funktioniert. Gleiches gilt fürkeys()
Werdenlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
da python3 die keys () -Methode zu einem Iterator macht und das Löschen von diktierten Elementen während der Iteration nicht zulässt. Durch Hinzufügen eines list () -Aufrufs verwandeln Sie den keys () -Iterator in eine Liste. Wenn Sie sich also im Hauptteil der for-Schleife befinden, iterieren Sie nicht mehr über das Wörterbuch selbst.Sie können dies auch in zwei Schritten tun:
Mein Lieblingsansatz ist normalerweise, einfach ein neues Diktat zu machen:
quelle
remove
Loop-Ansatz mehr.for k in [k for k in mydict if k == val]: del mydict[k]
Sie können eine Sammlung nicht ändern, während Sie sie wiederholen. Auf diese Weise liegt der Wahnsinn - vor allem, wenn Sie das aktuelle Element löschen und löschen könnten, müsste der Iterator weitermachen (+1) und der nächste Aufruf
next
würde Sie darüber hinaus führen (+2), also würden Sie Überspringen Sie am Ende ein Element (das direkt hinter dem von Ihnen gelöschten). Sie haben zwei Möglichkeiten:.keys()
et al. Verwenden (übergeben Sie in Python 3 den resultierenden Iterator anlist
). Könnte jedoch räumlich sehr verschwenderisch sein.mydict
wie gewohnt und speichern Sie die zu löschenden Schlüssel in einer separaten Sammlungto_delete
. Wenn Sie mit dem Iterieren fertig sindmydict
, löschen Sie alle Elementeto_delete
ausmydict
. Spart beim ersten Ansatz etwas Platz (abhängig davon, wie viele Schlüssel gelöscht wurden und wie viele verbleiben), erfordert aber auch einige weitere Zeilen.quelle
You can't modify a collection while iterating it.
Dies ist nur für Diktate und Freunde richtig, aber Sie können Listen während der Iteration ändern:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
ist nur für Diktat und Freunde richtig, während esshouldn't
für Listen sein sollte.Iterieren Sie stattdessen über eine Kopie, z. B. die von
items()
:quelle
del v
direkt, also haben Sie eine Kopie von jedem v erstellt, das Sie nie verwenden werden, und Sie müssen sowieso per Schlüssel auf die Elemente zugreifen.dict.keys()
ist eine bessere Wahl.v
als Kriterium für das Löschen verwenden müssen.dict.items()
eher einen Iterator als eine Kopie zurück. Siehe Kommentar für Blair ‚s Antwort , die (leider) auch Python 2 Semantik annimmt.Es ist am saubersten zu verwenden
list(mydict)
:Dies entspricht einer parallelen Struktur für Listen:
Beide arbeiten in Python2 und Python3.
quelle
Sie können ein Wörterbuchverständnis verwenden.
d = {k:d[k] for k in d if d[k] != val}
quelle
d
.Wenn Sie mit python3 auf dic.keys () iterieren, wird der Fehler in der Wörterbuchgröße ausgelöst. Sie können diese alternative Methode verwenden:
Getestet mit Python3 funktioniert es einwandfrei und der Fehler " Wörterbuch hat während der Iteration die Größe geändert " wird nicht ausgelöst :
quelle
Sie können zuerst eine Liste der zu löschenden Schlüssel erstellen und dann über diese Liste iterieren, um sie zu löschen.
quelle
Es gibt eine Möglichkeit, die geeignet sein kann, wenn sich die zu löschenden Elemente immer am "Anfang" der Diktationsiteration befinden
Der "Anfang" ist garantiert nur für bestimmte Python-Versionen / -Implementierungen konsistent. Zum Beispiel aus den Neuerungen in Python 3.7
Auf diese Weise wird eine Kopie des Diktats vermieden, die viele der anderen Antworten zumindest in Python 3 nahe legen.
quelle
Ich habe die oben genannten Lösungen in Python3 ausprobiert, aber diese scheint die einzige zu sein, die für mich funktioniert, wenn Objekte in einem Diktat gespeichert werden. Grundsätzlich erstellen Sie eine Kopie Ihres dict () und wiederholen diese, während Sie die Einträge in Ihrem ursprünglichen Wörterbuch löschen.
quelle