8000 bpo-40755: Add missing multiset operations to Counter() by rhettinger · Pull Request #20339 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-40755: Add missing multiset operations to Counter() #20339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Handle iterable inputs. Add some tests
  • Loading branch information
rhettinger committed May 24, 2020
commit 6a471a1c021ed48163f2e0e8cfd0b943f36099b6
10 changes: 9 additions & 1 deletion Lib/collections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -894,18 +894,26 @@ def isequal(self, other):
Unlike the __eq__() method, this test ignores counts that
are zero or negative.
'''
if not isinstance(other, Counter):
other = Counter(other)
return +self == +other

def issubset(self, other):
'True if positive counts in self <= counts in other.'
if not isinstance(other, Counter):
other = Counter(other)
return not self - other

def issuperset(self, other):
'True if positive counts in self >= counts in other.'
if not isinstance(other, Counter):
other = Counter(other)
return not other - self

def isdisjoint(self, other):
'True is none of the elements in self overlap with other'
if not isinstance(other, Counter):
other = Counter(other)
return not self & other

# Rich comparison operators for multiset subset and superset tests
Expand All @@ -920,7 +928,7 @@ def __lt__(self, other):
'Rich comparison operators have been deliberately omitted. '
'Use the isequal(), issubset(), and issuperset() methods instead.')
__le__ = __gt__ = __ge__ = __lt__


########################################################################
### ChainMap
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import operator
import pickle
from random import choice, randrange
from itertools import product, chain, combinations
import string
import sys
from test import support
Expand Down Expand Up @@ -2219,6 +2220,25 @@ def test_helper_function(self):
self.assertTrue(c.called)
self.assertEqual(dict(c), {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r':2 })

def test_multiset_operations_equivalent_to_set_operations(self):
# When the multiplicities are all zero or one, multiset operations
# are guaranteed to be equivalent to the corresponding operations
# for regular sets.
s = list(product('abc', range(2)))
powerset = chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
counters = [Counter(dict(groups)) for groups in powerset]
for cp, cq in product(counters, repeat=2):
sp = set(cp.elements())
sq = set(cq.elements())
self.assertEqual(set(cp + cq), sp | sq)
self.assertEqual(set(cp - cq), sp - sq)
self.assertEqual(set(cp | cq), sp | sq)
self.assertEqual(set(cp & cq), sp & sq)
self.assertEqual(cp.isequal(cq), sp == sq)
self.assertEqual(cp.issubset(cq), sp.issubset(sq))
self.assertEqual(cp.issuperset(cq), sp.issuperset(sq))
self.assertEqual(cp.isdisjoint(cq), sp.isdisjoint(sq))


################################################################################
### Run tests
Expand Down
0