Comment faire pour supprimer des éléments à partir d'un dictionnaire lors de l'itération sur elle?
Est-il légitime de supprimer des éléments à partir d'un dictionnaire en Python lors de l'itération sur elle?
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 répondent pas à une certaine condition dans le dictionnaire, au lieu de créer un nouveau dictionnaire qui est un sous-ensemble de l'être itéré.
Est-ce une bonne solution? Il y a plus élégant/efficaces?
- Une question connexe, avec des réponses très intéressantes: stackoverflow.com/questions/9023078/....
- On pouvait en avoir essayé facilement. Si elle échoue, elle n'est pas légitime.
- On pouvait en avoir essayé facilement... et facilement rien appris de valeur. Si elle réussit, elle n'est pas nécessairement légitime. Les cas limites et inattendu réserves abondent. Cette question est non-trivial d'intérêt pour tous les Pythoneux. À la main en agitant le licenciement de l'ordre de "que l'On pouvait avoir essayé facilement!" est inutile et contraire à l'esprit inquisiteur de stackoverflow enquête.
- Après avoir pris connaissance de maxdu question connexe, je suis d'accord. Vous avez probablement juste de vouloir lire attentivement cette troublante en profondeur de la question et ses réponses écrites à la place. Votre Pythonic esprit sera soufflé.
- Test d'une idée par vous-même avant de le présenter ici est un peu dans l'esprit de stackoverflow si je ne me trompe pas. C'était tout ce que je voulais transmettre. Désolé si il n'y a eu aucune perturbation à cause de cela. Aussi je pense que c'est une bonne question et ne pas downvote il. J'aime la réponse de Jochen Ritzel la plupart. Je ne pense pas que l'on doit faire tous ces trucs pour supprimer à la volée lors de la suppression, dans une seconde étape est beaucoup plus simple. Que devrait être la préférée de mon point de vue.
- Muette observation: toute Votre boucle est une sorte de vaine si vous êtes à la recherche d'une clé spécifique. Vous pouvez le remplacer avec
try: del mydict[val]
except KeyError: pass
ou comme un one-liner, avecmydict.pop(val, None)
, qui seront tous deuxO(1)
activités, de ne pasO(n)
. La question est toujours valable même si la condition de la suppression est plus que juste "égale à une certaine valeur" si.
Vous devez vous connecter pour publier un commentaire.
EDIT:
Cette réponse ne fonctionnera pas pour Python3 et donnera une
RuntimeError
.Cela se produit parce que
mydict.keys()
retourne un itérateur pas une liste.Comme l'a souligné dans les commentaires simplement de convertir
mydict.keys()
à une liste parlist(mydict.keys())
et cela devrait fonctionner.Un simple test dans la console affiche vous ne pouvez pas modifier un dictionnaire lors de l'itération sur elle:
Comme indiqué dans delnan réponse, de supprimer des entrées provoque des problèmes lors de l'itérateur essaie de passer à l'entrée suivante. Au lieu de cela, utilisez la
keys()
méthode pour obtenir une liste des touches et de travail avec l':Si vous avez besoin de supprimer sur la base des éléments de valeur, utilisez la
items()
plutôt la méthode:for k, v in list(mydict.items()):
qui fonctionne très bien en Python 3. De même pourkeys()
devenirlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
que python3 rend la méthode keys() un itérateur, et refuse également de supprimer dict éléments au cours d'une itération. Par l'ajout d'une liste() appel vous activez les touches() itérateur dans une liste. Donc quand vous êtes dans le corps de la boucle, vous n'êtes plus à parcourir le dictionnaire lui-même.list
faire une copie de clés, ou seul point à chacun d'entre eux?iterator
dans une liste dekeys
.Vous pouvez aussi le faire en deux étapes:
Mon approche préférée est généralement juste à faire un nouveau dict:
remove
boucle approche plus.for k in [k for k in mydict if k == val]: del mydict[k]
Vous ne pouvez pas modifier une collection tout en évoluant d'elle. De cette façon se trouve la folie - et plus particulièrement, si vous avez été autorisé à supprimer et supprimer l'élément en cours, l'itérateur aurait à se déplacer sur le (+1) et le prochain appel à
next
vous prendrait-delà (+2), de sorte que vous ne finissent par sauter un seul élément (celui qui est juste derrière celui que vous avez supprimés). Vous avez deux options:.keys()
et al pour cela (en Python 3, passer le résultant itérateur pourlist
). Pourrait être très le gaspillage de l'espace-sage que.mydict
comme d'habitude, l'économie de l'clés à supprimer dans une autre collectionto_delete
. Lorsque vous avez terminé l'itérationmydict
, supprimer tous les éléments dansto_delete
demydict
. Permet de gagner (en fonction du nombre de touches sont supprimés et combien de séjour), au cours de la première approche, mais aussi nécessite un peu plus de lignes.You can't modify a collection while iterating it.
c'est juste correct pour les dicts et les amis, mais vous pouvez modifier des listes au cours d'une 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 correct uniquement pour les dict et amis, alors qu'il devrait êtreshouldn't
pour les listes.Itérer sur une copie à la place, tels que celui retourné par
items()
:del v
directement, si vous avez fait une copie de chaque v qui vous n'allez pas l'utiliser et que vous avez accès à des éléments clés de toute façon.dict.keys()
est un meilleur choix.v
comme un critère de suppression.dict.items()
retourne un itérateur, plutôt qu'une copie. Voir le commentaire de Blairdu répondre, qui (malheureusement) suppose également de Python 2 de la sémantique.C'est plus propre d'utiliser
list(mydict)
:Cela correspond à une structure parallèle pour les listes:
À la fois le travail en python2 et python3.
Avec python3, itérer sur les dic.les touches() va augmenter la taille du dictionnaire d'erreur. Vous pouvez utiliser cette alternative:
Testé avec python3, il fonctionne très bien et l'Erreur "dictionnaire changé de taille au cours d'une itération" n'est pas évoqué:
Je l'utilise quand, à partir d'un dictionnaire à l'aide de beaucoup de mémoire, je veux construire un autre dictionnaire (contenant la modification de la première) sans faire de "copier" et la surcharge de la mémoire RAM.
Vous pouvez utiliser un dictionnaire, la compréhension.
d = {k:d[k] for k in d if d[k] != val}
Vous pourriez d'abord créer une liste de clés à supprimer, puis itérer sur la liste de les supprimer.
Il y a un moyen qui peut être adapté si les articles que vous souhaitez supprimer sont toujours au "début" de la dict itération
Le "début" n'est garanti que pour être cohérent pour certaines versions de Python/implémentations. Par exemple à partir de Ce qui est Nouveau En Python 3.7
De cette manière évite une copie de la dict que beaucoup d'autres réponses suggèrent, au moins en Python 3.
J'ai essayé les solutions ci-dessus en Python3, mais celui-ci semble être le seul à travailler pour moi lors de stocker des objets dans un dict. Fondamentalement, vous faites une copie de votre dict() et l'itération de plus que lors de la suppression d'entrées dans votre dictionnaire original.