Czy legalne jest usuwanie elementów ze słownika w Pythonie podczas iteracji?
Na przykład:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
Chodzi o to, aby usunąć ze słownika elementy niespełniające określonych warunków, zamiast tworzyć nowy słownik, który jest podzbiorem iterowanego.
Czy to dobre rozwiązanie? Czy istnieją bardziej eleganckie / wydajne sposoby?
scripting
dictionary
python
Trilarion
źródło
źródło
Odpowiedzi:
EDYTOWAĆ:
Ta odpowiedź nie będzie działać dla Python3 i da
RuntimeError
.Dzieje się tak, ponieważ
mydict.keys()
zwraca iterator, a nie listę. Jak wskazano w komentarzach, wystarczy przekonwertowaćmydict.keys()
na listęlist(mydict.keys())
i powinna działać.Prosty test w konsoli pokazuje, że nie można modyfikować słownika podczas iteracji:
Jak stwierdzono w odpowiedzi delnana, usuwanie wpisów powoduje problemy, gdy iterator próbuje przejść do następnego wpisu. Zamiast tego użyj
keys()
metody, aby uzyskać listę kluczy i pracować z tym:Jeśli chcesz usunąć na podstawie wartości pozycji, użyj
items()
metody:źródło
for k, v in list(mydict.items()):
która działa dobrze w Pythonie 3. To samo dlakeys()
stawania sięlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
ponieważ python3 sprawia, że metoda keys () jest iteratorem, a także zabrania usuwania elementów dict podczas iteracji. Dodając wywołanie list (), zmieniasz iterator keys () w listę. Więc kiedy jesteś w ciele pętli for, nie iterujesz już samego słownika.Możesz to zrobić w dwóch krokach:
Moim ulubionym podejściem jest zwykle po prostu nowy dykt:
źródło
remove
podejście do pętli.for k in [k for k in mydict if k == val]: del mydict[k]
Nie można modyfikować kolekcji podczas iteracji. W ten sposób leży szaleństwo - przede wszystkim, jeśli pozwolono by ci usunąć i usunąć bieżący element, iterator musiałby przejść dalej (+1), a następne wezwanie
next
zabrałoby cię poza to (+2), więc w końcu pomijam jeden element (ten zaraz za tym, który usunąłeś). Masz dwie opcje:.keys()
et al (w Pythonie 3 przekaż wynikowy iteratorlist
). Może to być bardzo marnotrawne pod względem przestrzennym.mydict
jak zwykle, zapisując klucze do usunięcia w osobnej kolekcjito_delete
. Po zakończeniu iteracjimydict
usuń wszystkie elementyto_delete
zmydict
. Oszczędza trochę (w zależności od tego, ile kluczy zostało usuniętych i ile pozostało) miejsca w pierwszym podejściu, ale wymaga również kilku dodatkowych wierszy.źródło
You can't modify a collection while iterating it.
jest to poprawne w przypadku nagrań i znajomych, ale podczas iteracji możesz modyfikować listy:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
jest poprawny tylko dla nagrań i przyjaciół, podczas gdy powinien byćshouldn't
dla list.Zamiast tego powtarzaj kopię, taką jak ta zwrócona przez
items()
:źródło
del v
bezpośrednio, więc zrobiłeś kopię każdego v, którego nigdy nie będziesz używać i i tak musisz uzyskać dostęp do elementów według klucza.dict.keys()
jest lepszym wyborem.v
jako kryterium do usunięcia.dict.items()
zwraca iterator zamiast kopii. Zobacz komentarze do Blair „s odpowiedzi , który (niestety) przyjmuje również Python 2 semantykę.Najczystszy w użyciu
list(mydict)
:Odpowiada to równoległej strukturze list:
Oba działają w python2 i python3.
źródło
Możesz użyć słownika.
d = {k:d[k] for k in d if d[k] != val}
źródło
d
w miejscu.W przypadku python3, iteracja na dic.keys () podniesie błąd rozmiaru słownika. Możesz użyć tego alternatywnego sposobu:
Testowany z python3, działa dobrze i nie pojawia się komunikat o błędzie „ słownik zmienił rozmiar podczas iteracji ”:
źródło
Możesz najpierw zbudować listę kluczy do usunięcia, a następnie iterować tę listę, usuwając je.
źródło
Istnieje sposób, który może być odpowiedni, jeśli elementy, które chcesz usunąć, zawsze znajdują się na „początku” iteracji nagrania
„Początek” jest gwarantowany tylko w przypadku niektórych wersji / implementacji języka Python. Na przykład z Co nowego w Pythonie 3.7
W ten sposób unika się kopii dyktu, którą sugeruje wiele innych odpowiedzi, przynajmniej w Pythonie 3.
źródło
Wypróbowałem powyższe rozwiązania w Python3, ale wydaje się, że to jedyne, które działa dla mnie podczas przechowywania obiektów w nagraniu. Zasadniczo tworzysz kopię swojego dict () i iterujesz ją, usuwając wpisy z oryginalnego słownika.
źródło