Python 带过滤器、减法器或类似装置的计数器

Python 带过滤器、减法器或类似装置的计数器,python,collections,filter,counter,subtraction,Python,Collections,Filter,Counter,Subtraction,我有一个计数器(来自集合),希望过滤掉一组不需要的项目。结果应该是一个新的计数器(或者如果您愿意,可以就地执行),其中只包含与属性不匹配的项。我尝试在计数器上使用过滤器,但结果不再是计数器,而只是列表。我还尝试从计数器中减去集合中不需要的项目,但该操作没有实现。减去一个计数器是可行的,但我没有第二个计数器,创建它基本上就是我要执行的任务 Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ]) → Counter({4: 6, 5: 5,

我有一个
计数器
(来自
集合
),希望过滤掉一组不需要的项目。结果应该是一个新的计数器(或者如果您愿意,可以就地执行),其中只包含与属性不匹配的项。我尝试在
计数器上使用
过滤器
,但结果不再是
计数器
,而只是
列表
。我还尝试从
计数器
中减去
集合
中不需要的项目,但该操作没有实现。减去一个
计数器
是可行的,但我没有第二个
计数器
,创建它基本上就是我要执行的任务

Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
→ Counter({4: 6, 5: 5, 3: 4, 6: 3, 2: 2, 1: 1, 7: 1})
现在我想从这个计数器中删除所有
2
3
值,因此结果应该是

Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
以下是我的方法:

filter(lambda x: x not in (2, 3), c)
→ [1, 4, 5, 6, 7]
但我不想要一份清单

c - set([ 2, 3 ])
→ TypeError: unsupported operand type(s) for -: 'Counter' and 'set'
我可以使用sth在
计数器
中迭代未打包的元素列表,如下所示:

Counter(x for x in c.elements() if x not in (2, 3))
→ Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
Counter({ k: v for k, v in c.iteritems() if k not in (2, 3) })
但这显然是不必要的巨额成本

我找到的唯一(不是很好的)解决方案是这样的麻烦:

Counter(x for x in c.elements() if x not in (2, 3))
→ Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
Counter({ k: v for k, v in c.iteritems() if k not in (2, 3) })
还有什么更好、更简单、更易读的东西我忽略了吗


为什么实现的
计数器没有一个简单的减法运算符,可以与
集合一起使用呢?

只需使用
del

>>> c = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
>>> c
Counter({4: 6, 5: 5, 3: 4, 6: 3, 2: 2, 1: 1, 7: 1})
>>> del c[2]
>>> del c[3]
>>> c
Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
>>>
>>> c = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
>>> c
Counter({4: 6, 5: 5, 3: 4, 6: 3, 2: 2, 1: 1, 7: 1})
>>> c - Counter({2:sys.maxint, 3:sys.maxint})
Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
为了好玩,您可以用另一个
计数器
减去较大的值以删除键,但最好还是坚持使用
del

>>> c = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
>>> c
Counter({4: 6, 5: 5, 3: 4, 6: 3, 2: 2, 1: 1, 7: 1})
>>> del c[2]
>>> del c[3]
>>> c
Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})
>>>
>>> c = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
>>> c
Counter({4: 6, 5: 5, 3: 4, 6: 3, 2: 2, 1: 1, 7: 1})
>>> c - Counter({2:sys.maxint, 3:sys.maxint})
Counter({4: 6, 5: 5, 6: 3, 1: 1, 7: 1})

您可以使用pop,它比使用del或字典理解更快

def alt():
    C = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4])
    for k in C.keys():
        if k in (2, 3):
            del C[k]

def alt2():
    C = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4])
    for k in C.keys():
        if k in (2, 3):
            C.pop(k)

def alt3():
    C = Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4])
    Counter({ k: v for k, v in c.iteritems() if k not in (2, 3) })
伊皮顿:

>>> %timeit alt()
100000 loops, best of 3: 9.66 µs per loop

>>> %timeit alt2()
100000 loops, best of 3: 8.64 µs per loop

>>> %timeit alt3()
100000 loops, best of 3: 11.3 µs per loop
试试这个:

from collections import Counter
c=Counter([ 1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4 ])
c2=Counter()
for x in c.most_common():
    if x[1]<2 or x[1]>3:
        c2[x[0]]+=x[1]
print(c2)
从集合导入计数器
c=计数器([1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4])
c2=计数器()
对于c中的x,最常见()
如果x[1]3:
c2[x[0]]+=x[1]
打印(c2)

是否会过滤列表并将其发送到计数器工作?如果您的意思是
计数器(filter(lambda x:x不在(2,3,c)中))
则:否。过滤器迭代计数器,这意味着它只迭代键;在这个过程中,金额被遗忘了。然后,对于每个剩余的键,结果总是有一个1。我的意思是你过滤这个列表
[1,2,3,4,5,6,7,6,5,4,3,2,3,4,5,6,5,4,3,4,5,4]
,然后将它传递给计数器。我没有这个列表(除了这里的小示例);它可能非常长。考虑诸如<代码>计数器({ 1:1000000 })< /COD>。我总是可以使用
c.elements()
创建这个列表(正如我在上面的问题中所说的),但我希望避免这样做,因为这样做成本很高。是的,我现在也发现了这一点,无论如何,谢谢。缺点是它只能在适当的地方工作,而对于完整的集合来说,删除它需要一个循环(一般来说,我更喜欢函数方法——在那个世界中引入bug的可能性更小)。(我刚刚发现我只需要集合中的值的计数器版本,而不需要集合中的值的计数器版本。我必须复制它并做两次,但这不是问题的一部分,只是我在这里的用例…@Alfe嗯,就我个人而言,我会坚持使用dict comprehension
计数器({k:v代表k,v代表c.iteritems()如果k不在(2,3)})
。我会让这个问题在一段时间内不被接受,以引起更多的注意。最终,如果没有更好的答案出现(我对此表示怀疑),那么你的答案应该被接受。当使用
timeit
时,你应该只将测试中的代码放入循环中。您还将测试数据创建放入其中,这将均衡所有结果,具体取决于此步骤的成本。但由于测试数据在所有情况下都是相同的,因此趋势应该保持不变。谢谢你的贡献!