All Articles

How to Use Counters in Python?

Python provides the Counter class for counting objects. The Counter class is part of the collections module and a subclass of the dict class (we can check the same by using the issubclass function, try running issubclass(Counter, dict)).

Counter helps us to determine frequency of objects. The following code counts the frequency of character in a string:

word = 'banana'
frequency = {}

for char in word:
    # we could have also used frequency[char] = frequency.get(char, 0) + 1
    if char in frequency:
        frequency[char] += 1
    else:
        frequency[char] = 1

print(frequency)

The above code prints:

{'b': 1, 'a': 3, 'n': 2}

Excercise for readers: Can we have used defaultdict to simplify the code?

The Counter class helps us to simplify this counting operation.

Creating a Counter Object

Counter can be created:

  • from an iterable (for example, list, string, tuple)
  • from another dictionary
  • using keyword arguments

Examples

From an iterable:

>>> from collections import Counter
>>> counter_from_string = Counter('banana')
>>> counter_from_string
Counter({'a': 3, 'n': 2, 'b': 1})
>>> counter_from_list = Counter([1, 2, 3, 3, 2])
Counter({2: 2, 3: 2, 1: 1})

From another dictionary:

>>> from collections import Counter
>>> custom_counter = Counter({'letters': 26, 'digits': 10})
>>> custom_counter
Counter({'letters': 26, 'digits': 10})

Using keyword arguments:

>>> from collections import Counter
>>> custom_counter = Counter(letters=26, digits=10)
>>> custom_counter
Counter({'letters': 26, 'digits': 10})

elements() Method

The .elements() method returns an iterator over elements repeating each as many times as its frequency. Elements are returned in the order they were encountered. If an element’s count is less than 1, it is ignored.

>>> counter_apple = Counter('apple')
>>> for c in counter_apple.elements():
...    print(c)
... 
a
p
p
l
e

>>> counter_amazon = Counter('amazon') 
>>> for c in counter_amazon.elements():
...    print(c)
... 
a
a
m
z
o
n

Accessing a Frequency

Since Counter is a subclass of dict, we can access the keys as we do in a dict (value = my_dict[key]).

Like a dictionary, we can also use the methods .keys(), .values(), and .items().

Example

>>> from collections import Counter

>>> frequencies = Counter('banana')
>>> frequencies['a']
3
>>> frequencies.get('a')
3
>>> for letter in frequencies:            
...     print(letter, frequencies[letter])
... 
b 1
a 3
n 2
>>> for letter, frequency in frequencies.items():
...     print(letter, frequency)
... 
b 1
a 3
n 2
>>> print(frequencies.keys())
dict_keys(['b', 'a', 'n'])
>>> print(frequencies.values()) 
dict_values([1, 3, 2])

Note that, unlike a dict, Counter doesn’t raise a KeyError if a key is not found. Instead, it returns 0.

>>> from collections import Counter

>>> frequencies = Counter('banana')
>>> frequencies['x']  # note that, 'x' is not a character of 'banana'
0

Updating Frequency of the Objects

Counter provides a method .update() to update the count/frequency of a Counter.

Example

>>> from collections import Counter

>>> frequencies = Counter('banana')
>>> frequencies
Counter({'a': 3, 'n': 2, 'b': 1})
>> frequencies.update(Counter('apple'))
>>> frequencies
Counter({'a': 4, 'n': 2, 'p': 2, 'b': 1, 'l': 1, 'e': 1})

The method update adds the frequency from a new Counter. In the above example, frequencies of letters from “apple” gets added to the frequencies of “banana”.

We can simply assign a new counter if we want it to reflect frequecies from a different Counter:

>>> from collections import Counter

>>> frequencies = Counter('banana')
>>> frequencies
Counter({'a': 3, 'n': 2, 'b': 1})
>> frequencies = Counter('apple')  # Simply assign a new Counter
>>> frequencies
Counter({'p': 2, 'a': 1, 'l': 1, 'e': 1})

Most Common Objects

The most_common method returns a list of n most common elements and their counts from the most common to least.

>>> Counter('mississippi').most_common(3)
[('i', 4), ('s', 4), ('p', 2)]

If we do not pass n or use None, it returns all elements in the counter. Elements with equal counts are printed in the order they were encountered (introduced in Python 3.7).

>>> Counter('mississippi').most_common()  
[('i', 4), ('s', 4), ('p', 2), ('m', 1)]

To get the least common objects, we can slice the result of most_common.

>>> Counter('mississippi').most_common()[:-3:-1]  
[('m', 1), ('p', 2)]

Counter Arithmetics

The Counter class provides various arithmetic operations. In the following examples, we will use two strings “amazon” and “amaze”. Here are their counts for easy reference.

letter Count in “amazon” Count in “amaze”
‘a’ 2 2
‘m’ 1 1
‘z’ 1 1
‘o’ 1 0
‘n’ 1 0
‘e’ 0 1

Addition

Addition adds two counter together. This is similar as the .update() method.

>>> counter_amazon = Counter('amazon')
>>> counter_amaze = Counter('amaze')
>>> counter_amazon + counter_amaze    
Counter({'a': 4, 'm': 2, 'z': 2, 'o': 1, 'n': 1, 'e': 1})
>>> counter_amazon.update(counter_amaze)
>>> counter_amazon
Counter({'a': 4, 'm': 2, 'z': 2, 'o': 1, 'n': 1, 'e': 1})  # note the result is same

One difference with the .update() is that update can return negative numbers which the addition operator doesn’t.

>>> c1 = Counter(x=2, y=-3)
>>> c2 = Counter(x=1, y=-2)
>>> c1 + c2  # note that, there is no count of y
Counter({'x': 3})
>>> c1.update(c2)
>>> c1  # count of y is also returned
Counter({'x': 3, 'y': -5})

Uniary addition adds the corresponding counter to an empty counter.

>>> c = Counter(x=3, y=-2)
>>> +c
Counter({'x': 3})

Subtraction

Subtraction subtracts two counters keeping only the positive counts (>=0).

>>> counter_amazon = Counter('amazon')
>>> counter_amaze = Counter('amaze')
>>> counter_amazon - counter_amaze
Counter({'o': 1, 'n': 1})

Note that in the above example, the count ‘e’: -1 and the zero count of ‘a’, ‘m’, and ‘z’ are omitted. If we want to keep the negative count as well, we can use the .subtract() method.

>>> counter_amazon = Counter('amazon')
>>> counter_amaze = Counter('amaze')     
>>> counter_amazon.subtract(counter_amaze)
>>> counter_amazon
Counter({'o': 1, 'n': 1, 'a': 0, 'm': 0, 'z': 0, 'e': -1})

Uniary subtraction subtracts the corresponding counter to an empty counter.

>>> c = Counter(x=3, y=-2)
>>> -c
Counter({'y': 2})

Intersection

Intersection returns the minimum of the corresponding counts.

>>> counter_amazon = Counter('amazon')
>>> counter_maze = Counter('maze')
>>> counter_amazon & counter_maze
Counter({'a': 1, 'm': 1, 'z': 1})

Union

Union returns the maximum of the corresponding counts.

>>> counter_amazon = Counter('amazon')
>>> counter_maze = Counter('maze')
>>> counter_amazon | counter_maze
Counter({'a': 2, 'm': 1, 'z': 1, 'o': 1, 'n': 1, 'e': 1})