【问题标题】:Adding counters deletes keys添加计数器删除键
【发布时间】:2014-03-20 04:12:25
【问题描述】:

见下文,为什么+= 的实现会炸掉我原来的计数器中的一个键?

>>> 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 接受可哈希项的迭代?

为了进一步混淆问题,counter 实现了 updatesubtract 方法,它们与 +- 运算符具有不同的行为。看来这个班级有身份危机!

计数器是字典还是袋子?

【问题讨论】:

    标签: python data-structures dictionary counter multiset


    【解决方案1】:

    Counters 一种多重集。来自Counter() documentation

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

    强调我的。

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

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

    [...]

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

    所以Counter 对象是both;字典包。然而,标准字典不支持加法,但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})
    

    【讨论】:

      【解决方案2】:

      来自source

      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__ 方法会快得多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-14
        • 2021-12-25
        • 2019-05-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多