negative "counts" in collections.Counter?

Vlastimil Brom vlastimil.brom at gmail.com
Mon Mar 8 06:13:31 EST 2010


2010/3/8 Raymond Hettinger <python at rcn.com>:
> On Mar 7, 5:46 pm, Steven D'Aprano <st... at REMOVE-THIS-
> cybersource.com.au> wrote:
>> Given that Counter supports negative counts, it looks to me that the
>> behaviour of __add__ and __sub__ is fundamentally flawed. You should
>> raise a bug report (feature enhancement) on the bug tracker.
>
> It isn't a bug.  I designed it that way.
> There were several possible design choices,
> each benefitting different use cases.
>...
> One possible choice (the one preferred by the OP) was to
> has addition and subtraction be straight adds and subtracts
> without respect to sign and to not support __and__ and __or__.
> Straight addition was already supported via the update() method.
> But no direct support was provided for straight subtractions
> that leave negative values.  Sorry about that.
>
> Instead the choice was to implement the four methods as
> multiset operations.  As such, they need to correspond
> to regular set operations.  For example, with sets:
>
>...
> Hopes this gives you some insight into the design choices.
>
>
> Raymond Hettinger
>
Thank you very much for the exhaustive explanation Raymond!
I very much suspected, there would be some exact reasoning behind it,
as these negative counts are explicitly handled in the code of these
methods.
I just happened to expect the straightforward addition and subtraction
and possibly the zero truncation or an exception in incompatible cases
(like elements() with floats, currently). This way also the negative
part would be available and the truncation possible.
I am by far not able to follow all of the mathematical background, but
even for zero-truncating multiset, I would expect the truncation on
input rather than on output of some operations. E.g. the following
seems surprising to me in context of the discarded negatives by
addition or subtraction:

>>> c1=collections.Counter({'a': -11, 'b': -8})
>>> c2=collections.Counter({'a': 3})
>>> c2-c1
Counter({'a': 14, 'b': 8})
>>>

Probably a kind of negative_update()  or some better named method will
be handy, like the one you supplied or simply the current module code
without the newcount > 0: ... condition. Or would it be an option to
have a keyword argument like zero_truncate=False which would influence
this behaviour? Or is some other method than elements() incompatible
with negative counts?
(I actually can imagine comparing negative counts on both sides. e.g.
in a secondary comparison of two wordlists with specific removed items
- comparing to the "master" list.)
Additionally, were issubset and issuperset considered for this
interface (not sure whether symmetric_difference would be applicable)?

Anyway, I recognise, that I can easily use a custom class for these
tasks, if these usecases are rare or non-standard for this general
collection object.
Thanks again,
  vbr



More information about the Python-list mailing list