如何在循环中删除Counter对象中的条目而不引发RuntimeError?

17 投票
4 回答
41789 浏览
提问于 2025-04-17 00:09
from collections import *
ignore = ['the','a','if','in','it','of','or']
ArtofWarCounter = Counter(ArtofWarLIST)
for word in ArtofWarCounter:
    if word in ignore:
        del ArtofWarCounter[word]

ArtofWarCounter是一个计数器对象,里面包含了《孙子兵法》中的所有单词。我想把ignore里列出的单词从ArtofWarCounter中删除。

错误追踪信息:

  File "<pyshell#10>", line 1, in <module>
    for word in ArtofWarCounter:
RuntimeError: dictionary changed size during iteration

4 个回答

1

请查看下面的问题,了解为什么你现在的方法不起作用:
在遍历列表时删除项目

简单来说,当你在遍历一个集合(比如列表或字典)的时候,不应该在这个集合里添加或删除任何东西。collections.Counterdict 的一个子类,下面是文档中关于 dict.iteritems() 的警告:

在使用 iteritems() 的时候,如果你在字典中添加或删除条目,可能会引发 RuntimeError,或者无法遍历所有条目。

19

不要对字典里的所有单词进行循环查找,这样效率很低。字典在查找时表现得更好。

你可以遍历 ignore 列表,删除那些已经存在的条目:

ignore = ['the','a','if','in','it','of','or']
for word in ignore:
    if word in ArtofWarCounter:
        del ArtofWarCounter[word]
20

为了尽量减少代码的修改,可以使用 list,这样你正在遍历的对象就和 Counter 分开了。

ignore = ['the','a','if','in','it','of','or']
ArtofWarCounter = Counter(ArtofWarLIST)
for word in list(ArtofWarCounter):
    if word in ignore:
        del ArtofWarCounter[word]

在 Python2 中,你可以用 ArtofWarCounter.keys() 来代替 list(ArtofWarCounter),但是既然写出更能适应未来变化的代码这么简单,为什么不这样做呢?

更好的做法是直接不去计算那些你想忽略的项目。

ignore = {'the','a','if','in','it','of','or'}
ArtofWarCounter = Counter(x for x in ArtofWarLIST if x not in ignore)

注意,我把 ignore 变成了一个 set,这样测试 x not in ignore 就会高效得多。

撰写回答