EXOR or symmetric difference for the Counter class

Paddy paddy3118 at googlemail.com
Tue Aug 17 18:27:45 EDT 2010


On Aug 17, 10:47 pm, Paddy <paddy3... at googlemail.com> wrote:
> On 17 Aug, 02:29, Raymond Hettinger <pyt... at rcn.com> wrote:
>
>
>
> > [Paddy]
>
> > > Lets say you have two *sets* of integers representing two near-copies
> > > of some system, then a measure of their difference could be calculated
> > > as:
>
> > > len(X.symmetric_difference(Y)) / (len(X) + len(Y)) * 100 %
>
> > > If the two collections of integers are allowed duplicates then you
> > > need a Counter/bag/multi-set type and the diff calculation I gave
> > > originally.
>
> > Thanks for sharing your use case.
>
> > It's unlikely that I will add this method to the Counter API because
> > the rarity of use case does not warrant the added API complexity.
> > IMO, adding a method like this makes the class harder to learn,
> > understand and remember.  It doesn't seem like much of a win over
> > using the existing alternatives:
>
> >  * (b - c) + (c - b)
> >  * (b | c) - (b & c)
> >  * DIY using the two counters as simple dicts
> >  * writing a subclass providing additional binary operations
>
> > I would like to see someone post a subclass to the ASPN Cookbook that
> > adds a number of interesting, though not common operations.  Your
> > symmetric_difference() method could be one.  A dot_product() operation
> > could be another.  Elementwise arithmetic is another option (we
> > already have add and subtract, but could possibly use multiply,
> > divide, etc).  Scaling operations are another possibility (multiple
> > all elements by five, for example).
>
> > The Counter() class has low aspirations.  It is a dictionary that
> > fills-in missing values with zero and is augmented by a handful of
> > basic methods for managing the counts.
>
> > Raymond
>
> I created this that could be an addition to the bottom of the Python 3
> collections.Counter class definition:
>
>     def __xor__(self, other):
>         ''' symmetric difference: Subtract count, but keep only abs
> results with non-zero counts.
>
>         >>> Counter('abbbc') ^ Counter('bccd')
>         Counter({'b': 2, 'a': 1, 'c': 1, 'd': 1})
>         >>> a, b = Counter('abbbc'), Counter('bccd')
>         >>> (a-b) + (b - a) == a ^ b
>         True
>
>         '''
>         if not isinstance(other, Counter):
>             return NotImplemented
>         result = Counter()
>         for elem in set(self) | set(other):
>             newcount = self[elem] - other[elem]
>             if newcount != 0:
>                 result[elem] = newcount if newcount > 0 else -newcount
>         return result
>
> - Paddy.

And heres the cartesian product/multiply:

    def __mul__(self, other):
        '''Multiply counts by an integer; or cartesioan product
        of two counters.

        >>> Counter('abbb') * 3
        Counter({'b': 9, 'a': 3})
        >>> Counter('12') * Counter('21')
        Counter({('2', '1'): 1, ('1', '2'): 1, ('1', '1'): 1, ('2',
'2'): 1})
        >>> Counter('122') * Counter('211')
        Counter({('2', '1'): 4, ('1', '1'): 2, ('2', '2'): 2, ('1',
'2'): 1})
        '''
        if isinstance(other, int):
            return Counter(**dict((k, v*other)
                                  for k,v in self.items()))
        elif isinstance(other, Counter):
            return Counter( (x, y)
                            for x in self.elements()
                            for y in other.elements() )
        else:
            return NotImplemented

(Although I don't have a use case for this one).

- Paddy.



More information about the Python-list mailing list