¿Cómo puedo evitar el error "RuntimeError: el diccionario cambió de tamaño durante la iteración"?

Resuelto user1530318 asked hace 12 años • 15 respuestas

Supongamos que tengo un diccionario de listas:

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

Ahora quiero eliminar pares clave-valor donde los valores son listas vacías. Probé este código:

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

pero esto da un error:

RuntimeError: dictionary changed size during iteration

Entiendo que no se pueden agregar ni eliminar entradas de un diccionario mientras se recorre en iteración. ¿Cómo puedo solucionar esta limitación para resolver el problema?


Consulte Modificar un dictado de Python mientras se itera sobre él para conocer las citas que pueden causar problemas y por qué.

user1530318 avatar Aug 14 '12 03:08 user1530318
Aceptado

En Python 3.x y 2.x puedes usar use listpara forzar la realización de una copia de las claves:

for i in list(d):

En Python 2.x, las llamadas .keyshacían una copia de las claves que podía iterar mientras modificaba dict:

for i in d.keys():

pero en Python 3.x, .keysdevuelve un objeto de vista , por lo que no solucionará el error.

Mark Byers avatar Aug 13 '2012 20:08 Mark Byers

Sólo necesitas usar copy:

De esta manera, itera sobre los campos del diccionario original y sobre la marcha puede cambiar el dictado deseado d. Funciona en cada versión de Python, por lo que es más claro.

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]}

(Por cierto, generalmente para iterar sobre la copia de su estructura de datos, en lugar de usar .copypara diccionarios o dividir [:]para listas, puede usar import copy-> copy.copy(para una copia superficial que es equivalente a copyla que admiten diccionarios o la división [:]que es compatible con listas) o copy.deepcopyen su estructura de datos.)

Alon Elharar avatar Mar 31 '2016 10:03 Alon Elharar

Simplemente use la comprensión del diccionario para copiar los elementos relevantes en un nuevo dictado:

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

Para esto en Python 2:

>>> 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]}
Maria Zverina avatar Aug 13 '2012 20:08 Maria Zverina