[Python-ideas] collections.Counter multiplication

Matthew Ruffalo mmr15 at case.edu
Thu May 30 02:52:16 CEST 2013


On 05/29/2013 08:06 PM, Steven D'Aprano wrote:
> On 30/05/13 06:17, James K wrote:
>> It should work like this
>>
>>      >>> from collections import Counter
>>      >>> Counter({'a': 1, 'b': 2}) * 2 # scalar
>>      Counter({'b': 4, 'a': 2})
>
> Under what circumstances would you do this?
>
> What is it about Counters that they should support multiplication when 
> no other mapping type does?
Counters are different from other mapping types because they provide a 
natural Python stdlib implementation of multisets -- the docs explicitly 
state that "The Counter class is similar to bags or multisets in other 
languages.". The class already has behavior that is different from other 
mapping types: Counter.__init__ can also take an iterable of hashable 
objects instead of another mapping, and Counter.update adds counts 
instead of replacing them.
>
> For what it is worth, the above is trivially doable using dict 
> comprehensions:
>
> py> from collections import Counter
> py> count = Counter({'a': 2, 'b': 3})
> py> Counter({k:v*2 for k,v in count.items()})
> Counter({'b': 6, 'a': 4})
>
>
>>      >>> Counter({'a': 1, 'b': 2}) * Counter({'c': 1, 'b': 2}) # 
>> multiplies
>> matching keys
>>      Counter({'b': 4})
>>
>>
>> This is intuitive behavior and therefore should be added.
>
> Not to me it isn't. I cannot guess what purpose this would hold, or 
> why you would want to do this.
>
>
>> I am unsure about
>> division as dividing by a non-existing key would be a division by 0,
>> although division by a scalar is straightforward.
>
> Oh, so now you're proposing division as well? I presume you would want 
> to support both / and // division, since they're both equally intuitive:
>
> Counter({'a': 10})/3
> => Counter({'a': 3.3333333333333333})
>
> Counter({'a': 10})//Counter({'a': 3, 'b': 4})
> => Counter({'a': 3, 'b': 0})
>
> What about other operations, like ** & | ^ >> << ? Is it your proposal 
> that Counters should support every operation that ints support?
>
Counters already support & and | for multiset intersection and union. 
 From http://docs.python.org/3/library/collections.html :

"""

>>>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)
Counter({'a': 2})
>>>c  &  d                        # intersection:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>>c  |  d                        # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

"""

The rationale for supporting multiplication by a scalar makes some sense 
when using Counters as multisets; multiplying by a another Counter is 
questionable.

MMR...


More information about the Python-ideas mailing list