Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit becd568

Browse files
committed
Issue #13121: Support in-place math operators for collections.Counter().
1 parent 3bb8be6 commit becd568

4 files changed

Lines changed: 86 additions & 1 deletion

File tree

Doc/library/collections.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ or subtracting from an empty counter.
293293
Counter({'b': 4})
294294

295295
.. versionadded:: 3.3
296-
Added support for unary plus and unary minus.
296+
Added support for unary plus, unary minus, and in-place multiset operations.
297297

298298
.. note::
299299

Lib/collections/__init__.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,69 @@ def __neg__(self):
683683
'''
684684
return Counter() - self
685685

686+
def _keep_positive(self):
687+
'''Internal method to strip elements with a negative or zero count'''
688+
nonpositive = [elem for elem, count in self.items() if not count > 0]
689+
for elem in nonpositive:
690+
del self[elem]
691+
return self
692+
693+
def __iadd__(self, other):
694+
'''Inplace add from another counter, keeping only positive counts.
695+
696+
>>> c = Counter('abbb')
697+
>>> c += Counter('bcc')
698+
>>> c
699+
Counter({'b': 4, 'c': 2, 'a': 1})
700+
701+
'''
702+
for elem, count in other.items():
703+
self[elem] += count
704+
return self._keep_positive()
705+
706+
def __isub__(self, other):
707+
'''Inplace subtract counter, but keep only results with positive counts.
708+
709+
>>> c = Counter('abbbc')
710+
>>> c -= Counter('bccd')
711+
>>> c
712+
Counter({'b': 2, 'a': 1})
713+
714+
'''
715+
for elem, count in other.items():
716+
self[elem] -= count
717+
return self._keep_positive()
718+
719+
def __ior__(self, other):
720+
'''Inplace union is the maximum of value from either counter.
721+
722+
>>> c = Counter('abbb')
723+
>>> c |= Counter('bcc')
724+
>>> c
725+
Counter({'b': 3, 'c': 2, 'a': 1})
726+
727+
'''
728+
for elem, other_count in other.items():
729+
count = self[elem]
730+
if other_count > count:
731+
self[elem] = other_count
732+
return self._keep_positive()
733+
734+
def __iand__(self, other):
735+
'''Inplace intersection is the minimum of corresponding counts.
736+
737+
>>> c = Counter('abbb')
738+
>>> c &= Counter('bcc')
739+
>>> c
740+
Counter({'b': 1})
741+
742+
'''
743+
for elem, count in self.items():
744+
other_count = other[elem]
745+
if other_count < count:
746+
self[elem] = other_count
747+
return self._keep_positive()
748+
686749

687750
########################################################################
688751
### ChainMap (helper for configparser and string.Template)

Lib/test/test_collections.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,27 @@ def test_multiset_operations(self):
932932
set_result = setop(set(p.elements()), set(q.elements()))
933933
self.assertEqual(counter_result, dict.fromkeys(set_result, 1))
934934

935+
def test_inplace_operations(self):
936+
elements = 'abcd'
937+
for i in range(1000):
938+
# test random pairs of multisets
939+
p = Counter(dict((elem, randrange(-2,4)) for elem in elements))
940+
p.update(e=1, f=-1, g=0)
941+
q = Counter(dict((elem, randrange(-2,4)) for elem in elements))
942+
q.update(h=1, i=-1, j=0)
943+
for inplace_op, regular_op in [
944+
(Counter.__iadd__, Counter.__add__),
945+
(Counter.__isub__, Counter.__sub__),
946+
(Counter.__ior__, Counter.__or__),
947+
(Counter.__iand__, Counter.__and__),
948+
]:
949+
c = p.copy()
950+
c_id = id(c)
951+
regular_result = regular_op(c, q)
952+
inplace_result = inplace_op(c, q)
953+
self.assertEqual(inplace_result, regular_result)
954+
self.assertEqual(id(inplace_result), c_id)
955+
935956
def test_subtract(self):
936957
c = Counter(a=-5, b=0, c=5, d=10, e=15,g=40)
937958
c.subtract(a=1, b=2, c=-3, d=10, e=20, f=30, h=-50)

Misc/NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ Library
488488
in os.kill().
489489

490490
- Add support for unary plus and unary minus to collections.Counter().
491+
Issue #13121: Also an support for inplace math operators.
491492

492493
- Issue #12683: urlparse updated to include svn as schemes that uses relative
493494
paths. (svn from 1.5 onwards support relative path).

0 commit comments

Comments
 (0)