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