Simplify explanation of multiset operations by removing restrictions on negative inputs.
This commit is contained in:
parent
63b3a97a2a
commit
e0d1b9f11f
|
@ -253,16 +253,18 @@ Common patterns for working with :class:`Counter` objects::
|
|||
c.items() # convert to a list of (elem, cnt) pairs
|
||||
Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
|
||||
c.most_common()[:-n:-1] # n least common elements
|
||||
c += Counter() # remove zero and negative counts
|
||||
|
||||
Several multiset mathematical operations are provided for combining
|
||||
:class:`Counter` objects. Multisets are like regular sets but allowed to
|
||||
:class:`Counter` objects. Multisets are like regular sets but are allowed to
|
||||
contain repeated elements (with counts of one or more). Addition and
|
||||
subtraction combine counters by adding or subtracting the counts of
|
||||
corresponding elements. Intersection and union return the minimum and maximum
|
||||
of corresponding counts::
|
||||
of corresponding counts. All four multiset operations exclude results with
|
||||
zero or negative counts::
|
||||
|
||||
>>> c = Counter({'a': 3, 'b': 1})
|
||||
>>> d = Counter({'a': 1, 'b': 2})
|
||||
>>> c = Counter(a=3, b=1)
|
||||
>>> d = Counter(a=1, b=2)
|
||||
>>> c + d # add two counters together: c[x] + d[x]
|
||||
Counter({'a': 4, 'b': 3})
|
||||
>>> c - d # subtract (keeping only positive counts)
|
||||
|
@ -272,16 +274,6 @@ of corresponding counts::
|
|||
>>> c | d # union: max(c[x], d[x])
|
||||
Counter({'a': 3, 'b': 2})
|
||||
|
||||
All four multiset operations produce only positive counts (negative and zero
|
||||
results are skipped). If inputs include negative counts, addition will sum
|
||||
both counts and then exclude non-positive results. The other three operations
|
||||
are undefined for negative inputs::
|
||||
|
||||
>>> e = Counter(a=8, b=-2, c=0)
|
||||
>>> e += Counter() # remove zero and negative counts
|
||||
>>> e
|
||||
Counter({'a': 8})
|
||||
|
||||
.. seealso::
|
||||
|
||||
* `Bag class <http://www.gnu.org/software/smalltalk/manual-base/html_node/Bag.html>`_
|
||||
|
|
|
@ -314,8 +314,8 @@ class Counter(dict):
|
|||
if not isinstance(other, Counter):
|
||||
return NotImplemented
|
||||
result = Counter()
|
||||
for elem, count in self.items():
|
||||
newcount = count - other[elem]
|
||||
for elem in set(self) | set(other):
|
||||
newcount = self[elem] - other[elem]
|
||||
if newcount > 0:
|
||||
result[elem] = newcount
|
||||
return result
|
||||
|
|
|
@ -462,18 +462,19 @@ class TestCounter(unittest.TestCase):
|
|||
for i in range(1000):
|
||||
# test random pairs of multisets
|
||||
p = Counter(dict((elem, randrange(-2,4)) for elem in elements))
|
||||
p.update(e=1, f=-1, g=0)
|
||||
q = Counter(dict((elem, randrange(-2,4)) for elem in elements))
|
||||
for counterop, numberop, defneg in [
|
||||
(Counter.__add__, lambda x, y: x+y if x+y>0 else 0, True),
|
||||
(Counter.__sub__, lambda x, y: x-y if x-y>0 else 0, False),
|
||||
(Counter.__or__, max, False),
|
||||
(Counter.__and__, min, False),
|
||||
q.update(h=1, i=-1, j=0)
|
||||
for counterop, numberop in [
|
||||
(Counter.__add__, lambda x, y: max(0, x+y)),
|
||||
(Counter.__sub__, lambda x, y: max(0, x-y)),
|
||||
(Counter.__or__, lambda x, y: max(0,x,y)),
|
||||
(Counter.__and__, lambda x, y: max(0, min(x,y))),
|
||||
]:
|
||||
result = counterop(p, q)
|
||||
for x in elements:
|
||||
# all except __add__ are undefined for negative inputs
|
||||
if defneg or (p[x] >= 0 and q[x] >= 0):
|
||||
self.assertEqual(numberop(p[x], q[x]), result[x])
|
||||
self.assertEqual(numberop(p[x], q[x]), result[x],
|
||||
(counterop, x, p, q))
|
||||
# verify that results exclude non-positive counts
|
||||
self.assert_(x>0 for x in result.values())
|
||||
|
||||
|
|
Loading…
Reference in New Issue