455 votes

supprimer des éléments d'un dictionnaire en itérant dessus

Est-il légitime de supprimer des éléments d'un dictionnaire en Python tout en les itérant?

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 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? Y a-t-il des moyens plus élégants / efficaces?

Merci.

452voto

Blair Points 6090

Un simple test dans la console affiche vous ne pouvez pas modifier un dictionnaire lors de l'itération sur elle:

>>> mydict = {'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> for k, v in mydict.iteritems():
...    if k == 'two':
...        del mydict[k]
...
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

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 l' keys() méthode pour obtenir une liste des touches et de travail avec:

>>> for k in mydict.keys():
...    if k == 'two':
...        del mydict[k]
...
>>> mydict
{'four': 4, 'three': 3, 'one': 1}

Si vous avez besoin de supprimer sur la base des éléments de valeur, de l'utilisation de l' items() méthode de:

>>> for k, v in mydict.items():
...     if v == 3:
...         del mydict[k]
...
>>> mydict
{'four': 4, 'one': 1}

119voto

Jochen Ritzel Points 42916

Vous pouvez également le faire en deux étapes:

 remove = [k for k in mydict if k == val]
for k in remove: del mydict[k]
 

Mon approche préférée consiste généralement à créer un nouveau dict:

 # In Python 2.7 and up 
mydict = { k : v for k,v in mydict.iteritems() if k != val }
# old versions
mydict = dict((k,v) for k,v in mydict.iteritems() if k != val)
 

35voto

Itérer une copie à la place, telle que celle retournée par items() :

 for k, v in mydict.items():
 

27voto

delnan Points 52260

Vous ne pouvez pas modifier une collection lors de l'itération. 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 d' 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:

  • Copie de toutes les clés (ou des valeurs, ou les deux, selon ce que vous avez besoin), puis itérer sur ceux. Vous pouvez utiliser .keys() et al (en Python 3, passer le résultant itérateur d' list). Pourrait être très le gaspillage de l'espace-sage.
  • Parcourir mydict comme d'habitude, l'économie de l'clés à supprimer dans une autre collection to_delete. Lorsque vous avez terminé l'itération mydict, supprimer tous les éléments en to_delete de mydict. 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X