21

见下文,为什么+=在我原来的计数器中执行吹走一个键?

>>> c = Counter({'a': 0, 'b': 0, 'c': 0})
>>> c.items()
[('a', 0), ('c', 0), ('b', 0)]
>>> c += Counter('abba')
>>> c.items()
[('a', 2), ('b', 2)]

我认为这至少可以说是不礼貌的,“X 被计算为 0 次”和“我们甚至没有计算 Xs”之间存在很大差异。看起来collections.Counter根本不是一个计数器,它更像是一个多组。

但是计数器是 dict 的子类,我们可以用零值或负值构造它们Counter(a=0, b=-1):如果它实际上是一个“一袋东西”,这不是被禁止的吗,限制 init 接受一个可哈希项目的迭代?

为了进一步混淆问题,计数器实现update和方法对和操作员subtract具有不同的行为。看来这个班级有身份危机!+-

Counter 是字典还是袋子?

4

2 回答 2

12

Counters一种多重集。从Counter()文档中:

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

强调我的。

它进一步告诉您有关 s 的多集性质的更多详细信息Counter

注意:计数器主要设计用于使用正整数来表示运行计数;但是,注意不要不必要地排除需要其他类型或负值的用例。为了帮助解决这些用例,本节记录了最小范围和类型限制。

[...]

  • 多集方法仅适用于具有正值的用例。输入可能是负数或零,但只会创建具有正值的输出。没有类型限制,但是值类型需要支持加减比较。

所以Counter对象都是;字典包。然而,标准字典不支持加法,但Counters 支持,所以这并不是说Counters 在这里打破了字典设置的优先级。

如果您想保留零,请使用Counter.update()并传入Counter.elements()另一个对象的结果:

c.update(Counter('abba').elements())

演示:

>>> c = Counter({'a': 0, 'b': 0, 'c': 0})
>>> c.update(Counter('abba').elements())
>>> c
Counter({'a': 2, 'b': 2, 'c': 0})
于 2014-02-19T17:02:51.683 回答
10

源头上;

def __add__(self, other):
    '''Add counts from two counters.

    >>> Counter('abbb') + Counter('bcc')
    Counter({'b': 4, 'c': 2, 'a': 1})

    '''
    if not isinstance(other, Counter):
        return NotImplemented
    result = Counter()
    for elem, count in self.items():
        newcount = count + other[elem]
        if newcount > 0:
            result[elem] = newcount
    for elem, count in other.items():
        if elem not in self and count > 0:
            result[elem] = count
    return result

似乎 Counter 实现为删除总和为零非正键的键。由于默认值为零,并且源也为零,因此生成的 dict 不包含该键。

也许您可以通过更新获得相同的行为:

a.update(b)

似乎做你想做的事。可能会更慢,但手工实现该__add__方法会快得多。

于 2014-02-19T17:02:52.317 回答