Welcome, guest | Sign In | My Account | Store | Cart

Adds symmetric difference and cartesian product to the Counter class. I had a use case for the former and Raymond H. asked about the latter so I coded the latter from its Wikipedia description.

Python, 52 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import collections

class Counter(collections.Counter):

    def __xor__(self, other):
        ''' 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

    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

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

        >>> 3 * Counter('abbb')
        Counter({'b': 9, 'a': 3, 'c': 3})
        '''
        return self.__mul__(other)

The code in __mul__ was written without much thought for efficiency.

4 comments

Paddy McCarthy (author) 11 years, 3 months ago  # | flag

Aargh!! I forgot about copyright for the original python methods (all but __xor__ and __mul__ and __rmul__)!! Do i delete this??

Paddy McCarthy (author) 11 years, 3 months ago  # | flag

I have now elided the Python code for the body of the class that needs inserting from the original Python source file collections.py

Rogier Steehouder 11 years, 3 months ago  # | flag

Or even better:

import collections

class Counter(collections.Counter):
    # only your changes go here
Paddy McCarthy (author) 11 years, 3 months ago  # | flag

Thanks Rogier for your suggestion. I have updated the code.