Est-il légitime de supprimer des éléments d'un dictionnaire en Python tout en itérant dessus?
Par exemple:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
L'idée est de supprimer les éléments qui ne remplissent pas une certaine condition du dictionnaire, au lieu de créer un nouveau dictionnaire qui est un sous-ensemble de celui qui est itéré.
Est-ce une bonne solution? Existe-t-il des moyens plus élégants / efficaces?
scripting
dictionary
python
Trilarion
la source
la source
Réponses:
ÉDITER:
Cette réponse ne fonctionnera pas pour Python3 et donnera un
RuntimeError
.Cela se produit car
mydict.keys()
renvoie un itérateur et non une liste. Comme indiqué dans les commentaires, il suffit de convertirmydict.keys()
en listelist(mydict.keys())
et cela devrait fonctionner.Un simple test dans la console montre que vous ne pouvez pas modifier un dictionnaire en itérant dessus:
Comme indiqué dans la réponse de delnan, la suppression d'entrées provoque des problèmes lorsque l'itérateur essaie de passer à l'entrée suivante. Utilisez plutôt la
keys()
méthode pour obtenir une liste des clés et travaillez avec:Si vous devez supprimer en fonction de la valeur des éléments, utilisez
items()
plutôt la méthode:la source
for k, v in list(mydict.items()):
qui fonctionne bien en Python 3. Idem pourkeys()
devenirlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
car python3 fait de la méthode keys () un itérateur, et interdit également la suppression des éléments dict pendant l'itération. En ajoutant un appel list (), vous transformez l'itérateur keys () en liste. Ainsi, lorsque vous êtes dans le corps de la boucle for, vous n'itérez plus le dictionnaire lui-même.Vous pouvez également le faire en deux étapes:
Mon approche préférée est généralement de simplement faire un nouveau dict:
la source
remove
davantage l'approche en boucle.for k in [k for k in mydict if k == val]: del mydict[k]
Vous ne pouvez pas modifier une collection pendant son itération. De cette façon réside la folie - plus particulièrement, si vous étiez autorisé à supprimer et à supprimer l'élément en cours, l'itérateur devrait passer à (+1) et le prochain appel à vous
next
mènerait au-delà (+2), vous finissent par sauter un élément (celui juste derrière celui que vous avez supprimé). Vous avez deux options:.keys()
et al pour cela (en Python 3, passez l'itérateur résultant àlist
). Cela pourrait être très gaspillant en termes d'espace.mydict
comme d'habitude, en enregistrant les clés à supprimer dans une collection séparéeto_delete
. Une fois l'itération terminéemydict
, supprimez tous les élémentsto_delete
demydict
. Économise de l'espace (en fonction du nombre de clés supprimées et du nombre restant) sur la première approche, mais nécessite également quelques lignes supplémentaires.la source
You can't modify a collection while iterating it.
c'est juste correct pour les dict et les amis, mais vous pouvez modifier les listes pendant l'itération:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
Est toujours correct uniquement pour dict et amis, alors qu'il devrait l'êtreshouldn't
pour les listes.Répétez plutôt une copie, comme celle retournée par
items()
:la source
del v
directement, vous avez donc fait une copie de chaque v que vous n'allez jamais utiliser et vous devez de toute façon accéder aux éléments par clé.dict.keys()
est un meilleur choix.v
comme critère de suppression.dict.items()
renvoie un itérateur plutôt qu'une copie. Voir le commentaire pour la réponse de Blair , qui (malheureusement) suppose également la sémantique de Python 2.C'est le plus propre à utiliser
list(mydict)
:Cela correspond à une structure parallèle pour les listes:
Les deux fonctionnent en python2 et python3.
la source
Vous pouvez utiliser une compréhension de dictionnaire.
d = {k:d[k] for k in d if d[k] != val}
la source
d
sur place.Avec python3, itérer sur dic.keys () augmentera l'erreur de taille du dictionnaire. Vous pouvez utiliser cette méthode alternative:
Testé avec python3, cela fonctionne bien et l'erreur "La taille du dictionnaire a changé pendant l'itération " n'est pas déclenchée:
la source
Vous pouvez d'abord créer une liste de clés à supprimer, puis parcourir cette liste en les supprimant.
la source
Il existe un moyen qui peut convenir si les éléments que vous souhaitez supprimer sont toujours au "début" de l'itération du dict
Le «début» n'est garanti que pour être cohérent pour certaines versions / implémentations Python. Par exemple de Quoi de neuf dans Python 3.7
De cette façon, vous évitez une copie du dict que la plupart des autres réponses suggèrent, au moins en Python 3.
la source
J'ai essayé les solutions ci-dessus en Python3 mais celle-ci semble être la seule qui fonctionne pour moi lors du stockage d'objets dans un dict. Fondamentalement, vous faites une copie de votre dict () et vous répétez cela en supprimant les entrées de votre dictionnaire d'origine.
la source