How do I remove entries within a Counter object with a loop without invoking a RuntimeError?

落爺英雄遲暮 提交于 2019-11-29 18:02:58

问题


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 is a Counter object containing all the words from the Art of War. I'm trying to have words in ignore deleted from the ArtofWarCounter.

Traceback:

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

回答1:


For minimal code changes, use list, so that the object you are iterating over is decoupled from the Counter

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

In Python2, you can use ArtofWarCounter.keys() instead of list(ArtofWarCounter), but when it is so simple to write code that is futureproofed, why not do it?

It is a better idea to just not count the items you wish to ignore

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

note that I made ignore into a set which makes the test x not in ignore much more efficient




回答2:


Don't loop over all words of a dict to find a entry, dicts are much better at lookups.

You loop over the ignore list and remove the entries that exist:

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



回答3:


See the following question for why your current method is not working:
Remove items from a list while iterating

Basically you should not add or remove items from a collection while you are looping over it. collections.Counter is a subclass of dict, see the following warning in the documentation for dict.iteritems():

Using iteritems() while adding or deleting entries in the dictionary may raise a RuntimeError or fail to iterate over all entries.




回答4:


Use a counter, traverse the loop backwards (last to first), remove as needed. Loop until zero.



来源:https://stackoverflow.com/questions/7154312/how-do-i-remove-entries-within-a-counter-object-with-a-loop-without-invoking-a-r

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!