How to avoid “RuntimeError: dictionary changed size during iteration” error?
我用同样的错误检查了所有其他问题,但没有找到有帮助的解决方案。=/
我有一本列表词典:
1 | d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]} |
其中一些值为空。在创建这些列表的最后,我想在返回词典之前删除这些空列表。目前我正试图这样做:
1 2 3 | for i in d: if not d[i]: d.pop(i) |
但是,这给了我运行时错误。我知道,在迭代字典时,您不能在其中添加/删除元素……那么,解决这个问题的方法是什么?
在python 2.x中,调用
1 | for i in d.keys(): |
注意,这在python 3.x中不起作用,因为
另一种方法是使用
1 | for i in list(d): |
只需使用字典理解将相关项复制到新的字典中即可。
1 2 3 4 5 | >>> 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]} |
您只需使用"复制"即可:
通过这种方式,您可以迭代原始字典字段,并且可以动态地更改所需的dict(d dict)。它适用于每个Python版本,所以更清楚。
1 2 3 4 5 6 7 8 9 | 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]} |
我会尽量避免首先插入空列表,但通常会使用:
1 | d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty |
如果在2.7之前:
1 | d = dict( (k, v) for k,v in d.iteritems() if v ) |
或者只是:
1 2 3 | empty_key_vals = list(k for k in k,v in d.iteritems() if v) for k in empty_key_vals: del[k] |
对于Python 3:
1 | {k:v for k,v in d.items() if v} |
在这种情况下,我喜欢做一个深度复制,并在修改原始dict的同时循环该复制。
如果查找字段在列表中,可以在列表的for循环中枚举,然后指定位置作为索引以访问原始dict中的字段。
运行时错误的原因是,当数据结构在迭代过程中发生更改时,无法对其进行迭代。
实现您所要查找的内容的一种方法是使用list附加要删除的键,然后在遍历列表时使用字典上的pop函数删除已标识的键。
1 2 3 4 5 6 7 8 9 10 | 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) |