summaryrefslogtreecommitdiffstats
path: root/Lib/collections
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2020-05-31 21:57:42 (GMT)
committerGitHub <noreply@github.com>2020-05-31 21:57:42 (GMT)
commitb7d79b4f36787874128c439d38397fe95c48429b (patch)
tree0ac2cf41b34220a380dcad803676896a41b4cc33 /Lib/collections
parent2b201369b435a4266bda5b895e3b615dbe28ea6e (diff)
downloadcpython-b7d79b4f36787874128c439d38397fe95c48429b.zip
cpython-b7d79b4f36787874128c439d38397fe95c48429b.tar.gz
cpython-b7d79b4f36787874128c439d38397fe95c48429b.tar.bz2
bpo-40755: Add rich comparisons to Counter (GH-20548)
Diffstat (limited to 'Lib/collections')
-rw-r--r--Lib/collections/__init__.py122
1 files changed, 36 insertions, 86 deletions
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index 55fb46c..2acf672 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -691,6 +691,42 @@ class Counter(dict):
if elem in self:
super().__delitem__(elem)
+ def __eq__(self, other):
+ 'True if all counts agree. Missing counts are treated as zero.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return all(self[e] == other[e] for c in (self, other) for e in c)
+
+ def __ne__(self, other):
+ 'True if any counts disagree. Missing counts are treated as zero.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return not self == other
+
+ def __le__(self, other):
+ 'True if all counts in self are a subset of those in other.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return all(self[e] <= other[e] for c in (self, other) for e in c)
+
+ def __lt__(self, other):
+ 'True if all counts in self are a proper subset of those in other.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return self <= other and self != other
+
+ def __ge__(self, other):
+ 'True if all counts in self are a superset of those in other.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return all(self[e] >= other[e] for c in (self, other) for e in c)
+
+ def __gt__(self, other):
+ 'True if all counts in self are a proper superset of those in other.'
+ if not isinstance(other, Counter):
+ return NotImplemented
+ return self >= other and self != other
+
def __repr__(self):
if not self:
return '%s()' % self.__class__.__name__
@@ -886,92 +922,6 @@ class Counter(dict):
self[elem] = other_count
return self._keep_positive()
- def isequal(self, other):
- ''' Test whether counts agree exactly.
-
- Negative or missing counts are treated as zero.
-
- This is different than the inherited __eq__() method which
- treats negative or missing counts as distinct from zero:
-
- >>> Counter(a=1, b=0).isequal(Counter(a=1))
- True
- >>> Counter(a=1, b=0) == Counter(a=1)
- False
-
- Logically equivalent to: +self == +other
- '''
- if not isinstance(other, Counter):
- other = Counter(other)
- for elem in set(self) | set(other):
- left = self[elem]
- right = other[elem]
- if left == right:
- continue
- if left < 0:
- left = 0
- if right < 0:
- right = 0
- if left != right:
- return False
- return True
-
- def issubset(self, other):
- '''True if the counts in self are less than or equal to those in other.
-
- Negative or missing counts are treated as zero.
-
- Logically equivalent to: not self - (+other)
- '''
- if not isinstance(other, Counter):
- other = Counter(other)
- for elem, count in self.items():
- other_count = other[elem]
- if other_count < 0:
- other_count = 0
- if count > other_count:
- return False
- return True
-
- def issuperset(self, other):
- '''True if the counts in self are greater than or equal to those in other.
-
- Negative or missing counts are treated as zero.
-
- Logically equivalent to: not other - (+self)
- '''
- if not isinstance(other, Counter):
- other = Counter(other)
- return other.issubset(self)
-
- def isdisjoint(self, other):
- '''True if none of the elements in self overlap with those in other.
-
- Negative or missing counts are ignored.
-
- Logically equivalent to: not (+self) & (+other)
- '''
- if not isinstance(other, Counter):
- other = Counter(other)
- for elem, count in self.items():
- if count > 0 and other[elem] > 0:
- return False
- return True
-
- # Rich comparison operators for multiset subset and superset tests
- # have been deliberately omitted due to semantic conflicts with the
- # existing inherited dict equality method. Subset and superset
- # semantics ignore zero counts and require that p⊆q ∧ p⊇q ⇔ p=q;
- # however, that would not be the case for p=Counter(a=1, b=0)
- # and q=Counter(a=1) where the dictionaries are not equal.
-
- def _omitted(self, other):
- raise TypeError(
- 'Rich comparison operators have been deliberately omitted. '
- 'Use the isequal(), issubset(), and issuperset() methods instead.')
-
- __lt__ = __le__ = __gt__ = __ge__ = __lt__ = _omitted
-
########################################################################
### ChainMap