web-dev-qa-db-fra.com

Comment éviter l'erreur "RuntimeError: le dictionnaire a changé de taille pendant l'itération"?

J'ai vérifié toutes les autres questions avec la même erreur mais je n'ai trouvé aucune solution utile = /

J'ai un dictionnaire de listes:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

dans lequel certaines des valeurs sont vides. À la fin de la création de ces listes, je souhaite supprimer ces listes vides avant de retourner mon dictionnaire. Actuel j'essaye de faire ceci comme suit:

for i in d:
    if not d[i]:
        d.pop(i)

cependant, cela me donne l'erreur d'exécution. Je suis conscient que vous ne pouvez pas ajouter/supprimer des éléments dans un dictionnaire en itérant à travers celui-ci ... quel serait le moyen de contourner cela alors?

151
user1530318

Dans Python 2.x, l'appel de keys crée une copie de la clé sur laquelle vous pouvez effectuer une itération lors de la modification de dict:

for i in d.keys():

Notez que cela ne fonctionne pas dans Python 3.x car keys renvoie un itérateur au lieu d'une liste.

Une autre méthode consiste à utiliser list pour forcer la copie des clés. Celui-ci fonctionne également dans Python 3.x:

for i in list(d):
293
Mark Byers

Il suffit d’utiliser la compréhension du dictionnaire pour copier les éléments pertinents dans un nouveau dict

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}
24
Maria Zverina

Il vous suffit d'utiliser "copie":

De cette façon, vous parcourez les champs du dictionnaire d'origine et à la volée vous pouvez changer le dict désiré (d dict) . Cela fonctionne sur chaque version de Python, donc c'est plus clair.

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}
22
Alon Elharar

J'essayerais en premier lieu d'éviter d'insérer des listes vides, mais j'utiliserais généralement:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

Si antérieure à 2.7:

d = dict( (k, v) for k,v in d.iteritems() if v )

ou juste:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]
11
Jon Clements

Pour Python 3:

{k:v for k,v in d.items() if v}
8
ucyo

Vous ne pouvez pas parcourir un dictionnaire pendant qu'il change pendant la boucle for. Faites un casting pour lister et parcourir cette liste, ça marche pour moi.

    for key in list(d):
        if not d[key]: 
            d.pop(key)
1

Cette erreur d’exécution tient au fait qu’il est impossible d’itérer une itération dans une structure de données tant que celle-ci change au cours de l’itération.

Une façon d’atteindre ce que vous recherchez est d’utiliser list pour ajouter les clés à supprimer, puis d’utiliser la fonction pop sur dictionnaire pour supprimer la clé identifiée tout en parcourant la liste.

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []

for i in d:
        if not d[i]:
                pop_list.append(i)

for x in pop_list:
        d.pop(x)
print (d)
0
Rohit

Pour des situations comme celle-ci, j'aime bien faire une copie en profondeur et parcourir cette copie en modifiant le dict d'origine.

Si le champ de recherche se trouve dans une liste, vous pouvez énumérer la boucle for de la liste, puis spécifier la position en tant qu'index pour accéder au champ dans le dict d'origine.