有没有“更快的方法”从Counter中删除键值,值小于某个值?
我做了以下事情:
counter_dict = {k:v for k, v in counter_dict.items() if v > 5}
答案 0 :(得分:4)
当前代码的主要问题是调用.items
,它将创建所有项目的列表:
一个优化可能是使用Counter.iteritems
而不是.items
,以节省创建列表并再次迭代它的惩罚。
>>> from collections import Counter
>>> cnt = Counter("asbdasdbasdbadaasasdasadsa")
>>> {k:v for k,v in cnt.iteritems() if v > 5}
{'a': 10, 's': 7, 'd': 6}
另一个优化可能是不调用.items
方法,而是迭代键并使用键访问值:
>>> from collections import Counter
>>> cnt = Counter("asbdasdbasdbadaasasdasadsa")
>>> {k:cnt[k] for k in cnt if cnt[k] > 5}
{'a': 10, 's': 7, 'd': 6}
如果我们尝试 衡量ipython中与%timeit
的差异,请使用带有您提到的if条件的示例计数器 { {1}}获胜 :
iteritems
随着条件的变化:
In [1]: import random
In [2]: from collections import Counter
In [3]: MILLION = 10**6
In [4]: cnt = Counter(random.randint(0, MILLION) for _ in xrange(MILLION))
In [5]: %timeit {k:v for k, v in cnt.iteritems() if v < 5}
10 loops, best of 3: 140 ms per loop
In [6]: %timeit {k:v for k, v in cnt.items() if v**2 < 5}
1 loops, best of 3: 290 ms per loop
In [7]: %timeit {k:cnt[k] for k in cnt if cnt[k] < 5}
1 loops, best of 3: 272 ms per loop
答案 1 :(得分:0)
所以你最好不要每次都重新创建整个字典:
to_remove = set()
for key, value in counter_dict.viewitems():
if value <= 5:
to_remove.add(key)
for key in to_remove:
del counter_dict[key]
将“for”语句展开到更多行中并不一定意味着更少的性能。虽然在这种情况下可能没有太大的性能提升,但内存消耗至少应该会下降。
另一种选择是让你的“counter_dict”成为一个更聪明的对象 当计数值<= 5时,他知道不会产生它的值 - 这会使这一步“懒惰”。
事情(但不仅仅是 - 正确的事情是实现这一点 使用ABC元类 - collections.MutableMappingclass MyDict(dict):
def __init__(*args, **kw):
self.threshold = None
super(MyDict,self).__init__(*args, **kw)
def __getitem__(self, key):
value = super(MyDict, self).__getitem__(key)
if self.threshold is None or key > self.threshold:
return value
raise ItemError
# the same for __contains__ and other interesting methods
当你应该开始过滤时,你在dict中更改了“threshold”属性对象。这或多或少过度了 - 因为你的检查仍然会在稀释的时间内完成 - 但也许在消耗对象时,你处于异步/多线程工作负载可能会使它并行 - 但是如果你需要在不同的部分使用不同的阈值代码,它可能是一件好事。