对于collections.Counter,位与操作到底是做什么的?



最近有一个问题,正确的答案真的让我很惊讶,在两个计数器上使用&,然后"正确"。

From the docs:

计数器支持丰富的相等、子集和超集关系比较运算符:==、!=、<、<=、>、>=。所有这些测试都将缺失的元素视为计数为零,因此Counter(a=1) == Counter(a=1, b=0)返回true。

但这并没有涉及到&的细节。我写了一个小测试脚本:

from collections import Counter
from pprint import pp
cls = Counter  # `dict` fails: TypeError: unsupported operand type
o1 = cls(a=1,b=2,c=3,de=3,f=3,i1=9)
o2 = cls(a=1,b=2,c=3,de=5,f=6,i2=9)
res = o1 & o2
pp(dict(o1=o1,o2=o2,res=res))

输出为:

{'o1': Counter({'i1': 9, 'c': 3, 'de': 3, 'f': 3, 'b': 2, 'a': 1}),
'o2': Counter({'i2': 9, 'f': 6, 'de': 5, 'c': 3, 'b': 2, 'a': 1}),
'res': Counter({'c': 3, 'de': 3, 'f': 3, 'b': 2, 'a': 1})}

在我看来counter1 & counter2的意思是:

  • 计算两个键的交点
  • 对于常用键的值,计算min

我说的对吗?除了Counterset之外,其他标准库数据结构是否也定义了__and__(&, IIRC的后台)?

你的理解非常正确。如果您从引用的地方往下看几行,您将看到&Counter对象上的示例使用—您不需要深入到源代码中查找它:

交集和并集返回对应计数的最小值和最大值. ...

>>> c & d                       # intersection:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

容器文档状态:

提供了几个数学运算来组合Counter对象以产生多集(计数大于0的计数器)。加法和减法通过增加或减少相应元素的计数来组合计数器。交集和并集返回对应计数的最小值和最大值。相等和包含比较相应的计数。每个操作都可以接受带符号计数的输入,但输出将排除计数为零或更小的结果。

回答你关于其他字典派生重写&的问题,我认为没有。然而,set(文档在这里)使用&,|,-^来实现交集,并集,差和对称差。

根据官方文件:

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d                      # equality:  c[x] == d[x]
False
>>> c <= d                      # inclusion:  c[x] <= d[x]
False

还定义了一元操作:

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

最新更新