5

我需要 Python 中的类似包/多集的数据类型。我了解 collections.Counter 经常用于此目的。但是比较运算符似乎不起作用:

In [1]: from collections import Counter

In [2]: bag1 = Counter(a=1, b=2, c=3)

In [3]: bag2 = Counter(a=2, b=2)

In [4]: bag1 > bag2
Out[4]: True

这对我来说似乎是一个错误。我希望小于和大于运算符执行类似集合的子集和超集比较。但如果是这种情况,那么bag1 > bag2将是错误的,因为bag2包含一个额外的'a'. Counter 对象上似乎也没有子集/超集方法。所以我有两个问题:

  1. Counter 对象使用什么比较逻辑?
  2. 如何比较 Counter 对象的子集、超集、真子集和真超集?
4

2 回答 2

2

在 Python 2 上,比较回退到字典的默认排序顺序Counter是 的子类dict)。

当且仅当它们的排序(键,值)列表比较相等时,映射(字典)比较相等。[5] 平等以外的结果得到一致解决,但没有另外定义。[6]

在 Python 3 上,比较会引发TypeError

映射(字典)比较相等当且仅当它们具有相同的(键,值)对。顺序比较 ('<', '<=', '>=', '>') raise TypeError

于 2014-09-04T18:42:21.020 回答
1

这个悬而未决的问题很有趣:

如何比较 Counter 对象的子集、超集、真子集和真超集?

通过定义缺少的“丰富的比较方法”。您也可以使用自由函数,这将使客户端代码更加明确。

from collections import Counter

class PartiallyOrderedCounter(Counter):

    def __le__(self, other):
        """ Multiset inclusion """
        return all( v <= other[k] for k,v in self.items() )


    def __lt__(self, other):
        """ Multiset strict inclusion """
        return self <= other and self != other


    # TODO : __ge__ and __gt__
    # Beware : they CANNOT be written in terms of __le__ or __lt__


a = PartiallyOrderedCounter('abc')
b = PartiallyOrderedCounter('ab')
c = PartiallyOrderedCounter('abe')

assert a <= a
assert not a < a    
assert b <= a
assert b < a
assert not a < b    
assert not c <= a
assert not a <= c
于 2017-06-20T05:55:51.653 回答