Counter – Collections in Python

In Python, Counter is a subclass of dict that is part of the collections module. collections module in Python provides specialized container data types and offer alternatives to general-purpose built-in types like lists, dictionaries, and tuples. These container data types are designed to make them more efficient and flexible to manage data.

Counter

Counter is used to count hashable objects. It store the objects as dictionary keys and their counts as values. Counter is like a dictionary which is used for counting items and is very useful for frequency analysis, counting occurrences of elements, words in a document, or any other type of collection.

Syntax to create Counter object:

counter_object = collections.Counter(iterable, **kwds)

  • collections is a module in Python. Counter class is part of collections module. We need to import collections module to use Counter class in our program.
  • Counter() is the Counter class constructor
  • iterable (optional) is any sequential data type object, based on which Counter object will be created.
  • kwds (optional) are the keyword arguments that can be used to create Counter object.
  • Both iterable and kwds are optional parameters. If none of them is given, then empty Counter object will be created.
  • counter_object is the object returned

Counter Properties

  • Counter is a subclass of dict, it inherits all the standard dictionary methods and properties.
  • Elements as keys – Keys of a Counter are the elements of the given iterable or keyword arguments.
  • Counts as values – Values in the Counter represent the counts of each key.

Create Counter Object

In this program, we will create Counter object in following ways.

  1. Empty Counter object
  2. Counter object with list as iterable
  3. Counter object with string as iterable
  4. Counter object with dictionary as iterable
  5. Counter object with keyword arguments
print("create Counter object")
from collections import Counter                # import Counter from collection module

# Empty Counter object
empty_counter = Counter()
print(empty_counter)
print(type(empty_counter))

# Counter object from list
courses_counter = Counter(["Python","Python","Python","PowerBI"])
print(courses_counter)

# Counter object from string
shbytes_counter = Counter("shbytes")
print(shbytes_counter)

# Counter object from dictionary
mapping_counter = Counter({"c1":"PowerBI", "c2":"Python"})
print(mapping_counter)

# Counter object from keyword arguments
args_counter = Counter(courses=5, trainings=15)
print(args_counter)

# Counter object from iterable and keyword arguments
iter_keyword_counter = Counter({"c1":"AWS", "c2":"Python"}, courses=5, trainings=15)
print(iter_keyword_counter)

In this program, first we import Counter class from collections module. We have created Counter object in multiple ways.

  • Using Counter() to create empty object
  • Using Counter(["Python","Python","Python","PowerBI"]) to create Counter object from list
  • Using Counter("shbytes") to create Counter object from string
  • Using Counter({"c1":"PowerBI", "c2":"Python"}) to create Counter object from dictionary
  • Using Counter(courses=5, trainings=15) to create Counter object from keyword arguments
  • Using Counter({"c1":"AWS", "c2":"Python"}, courses=5, trainings=15) to create Counter object combining iterable and keyword arguments.

Program Output

create Counter object
Counter()
<class 'collections.Counter'>
# object created from list iterable
Counter({'Python': 3, 'PowerBI': 1})
# object created from string iterable
Counter({'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1})
# object created from dictionary iterable
Counter({'c2': 'Python', 'c1': 'PowerBI'})
# object created from keyword arguments
Counter({'trainings': 15, 'courses': 5})
# object created from dictionary and keyword arguments
Counter({'c1': 'AWS', 'c2': 'Python', 'courses': 5, 'trainings': 15})

Access Counter Object

Counter is a subclass of dict, it inherits all the standard dictionary methods and properties. We can access the elements from Counter object in similar way as we accessed from dictionary objects.

Access Counter element by key

#access Counter element by key
print("access Counter element by key")
from collections import Counter

# Create Counter object using dictionary
courses_counter = Counter(["AWS","Python","AWS","Data Science"]) 
print(courses_counter)

print(courses_counter["AWS"])      # Access element by key AWS
print(courses_counter["ML"])        # Access element by key ML

In this program, we have created a Counter object courses_counter using Counter(["AWS","Python","AWS","DataScience"]).

  • courses_counter["AWS"] will access the element for key AWS in the object and count value for AWS will be returned.
  • Using courses_counter["ML"] to access element for key ML in the object. ML is not present in the Counter object. Count 0 will be returned.

Program Output

access Counter element by key
Counter({'AWS': 2, 'Python': 1, 'Data Science': 1})
2     # For key AWS, present in Counter object
0     # For key ML, not present in Counter object

Iterate over Counter object

We can use elements() method to iterate over elements of Counter object. This iterates over elements, repeating each element as many times as its count value.

# iterator over Counter object elements, repeating each as many times as its count
# elements() methods
print("iterator over Counter object elements repeating each as many times as its count")
from collections import Counter

shbytes_counter = Counter("shbytes")
print(shbytes_counter)
# Using elements() method to iterate over Counter object elements
for element in shbytes_counter.elements():
	print(element)

In this program, we have created a Counter object using string like Counter("shbytes"). We are using shbytes_counter.elements() method and for loop to iterate over all elements of object.

Program Output

iterator over elements repeating each as many times as its count
Counter({'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1})
s
s
h
b
y
t
e

From the program, output, elements() method iterates over each element and repeat it as many times as its count value. e.g. element s count is 2 and it is repeated 2 times, element h count is 1 and it is repeated 1 time and similarly for other elements.

most_common() method

most_common() method is used to find the most common elements in the Counter. This returns list of n most common elements and their counts.

# return list of n most common elements and their counts
# most_common([n]
print("return list of n most common elements and their counts")
from collections import Counter

most_common_counter = Counter("shbytes")
print(most_common_counter)

print(most_common_counter.most_common(2))            # Access first 2 most common elements
print(most_common_counter.most_common()[:-4:-1])   # Access elements upto index -4 from right to left
print(most_common_counter.most_common())              # Access all elements

In this program, we are accessing most common elements from Counter object using most_common() method.

  • counter.most_common(2) will return first two elements from the Counter object.
  • counter.most_common()[:-4:-1] will return the elements up to end index -4 with step -1. It means elements will be taken from right to left up to index -4.
  • counter.most_common() will return all elements from Counter object.
return list of n most common elements and their counts
Counter({'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1})
# First two elements
[('s', 2), ('h', 1)]
# Elements from right to left up to index -4
[('e', 1), ('t', 1), ('y', 1)]
# All elements from Counter object
[('s', 2), ('h', 1), ('b', 1), ('y', 1), ('t', 1), ('e', 1)]

Update Counter Object

We can update existing Counter object using update([iterable-or-mapping]) method to increase or add the element into the object and subtract([iterable-or-mapping]) method to decrease or subtract the element from the Counter object.

update() method

update() method updates (increase or add new element) the count for the given key element in Counter object and if key does not exist then that key is added with positive count into the object.

# elements are counted from an iterable or added-in from another mapping (or counter)
# update([iterable-or-mapping])
print("elements are counted from an iterable or added-in from another mapping (or counter)")
from collections import Counter

# Create Counter Object
courses_counter = Counter(["Python","Python","PowerBI"])
print(courses_counter)

# Use update() method with list iterator
courses_counter.update(["Python","PowerBI"])
print(courses_counter)

# Use update() method with dictionary
courses_counter.update({"Python":2,"PowerBI":3})
print(courses_counter)

# Use update() method with another Counter object
courses_counter.update(Counter({"Python":2,"PowerBI":3}))
print(courses_counter)
  • We first import the Counter class from collections module
  • Using Counter(["Python","Python","PowerBI"]) create a Counter object courses_counter, which will have key as element from list and value as count of that element.
  • update(["Python","PowerBI"]) – Update Counter object with list iterator. Count of the keys will be increased for the element.
  • update({"Python":2,"PowerBI":3}) – Update Counter object with dictionary. Count of the keys will be increased with key count in dictionary.
  • update(Counter({"Python":2,"PowerBI":3})) – Update Counter with another Counter object. Count of the keys will be increased with key count in Counter object.
  • If element is not present in the Counter, then new element will be added from the given iterable or dictionary or Counter object.
elements are counted from an iterable or added-in from another mapping (or counter)
Counter({'Python': 2, 'PowerBI': 1})   # Original Counter Object
Counter({'Python': 3, 'PowerBI': 2})   # Update with list iterable
Counter({'Python': 5, 'PowerBI': 5})   # Update with dictionary object
Counter({'PowerBI': 8, 'Python': 7})   # Update with another Counter object

In this program, Counter object is updated multiple times with list, dictionary, or Counter object. Each time count value of the key increased (added new value to previous value) with the new value from the iterable.

subtract() method

subtract() method updates (decrease or subtract elements) the count for the given key element in Counter object and if key does not exist then that key is added with negative count into the object.

# elements are subtracted from an iterable or from another mapping (or counter)
# subtract([iterable-or-mapping])
print("elements are subtracted from an iterable or from another mapping (or counter)")
from collections import Counter

# Create Counter Object
courses_counter = Counter(["Python","Python","PowerBI"])
print(courses_counter)

# Use subtract() method with list iterator
courses_counter.subtract(["Python","PowerBI"])
print(courses_counter)

# Use subtract() method with dictionary
courses_counter.subtract({"Python":2,"PowerBI":3})
print(courses_counter)

# Use subtract() method with another Counter object
courses_counter.subtract(Counter({"Python":2,"PowerBI":3}))
print(courses_counter)
  • We first import the Counter class from collections module
  • Using Counter(["Python","Python","PowerBI"]) create a Counter object courses_counter, which will have key as element from list and value as count of that element.
  • subtract(["Python","PowerBI"]) – Update (subtract) Counter object with list iterator. Count of the keys will be decreased for the element.
  • subtract({"Python":2,"PowerBI":3}) – Update (subtract) Counter object with dictionary. Count of the keys will be decreased with key count in dictionary.
  • subtract(Counter({"Python":2,"PowerBI":3})) – Update (subtract) Counter with another Counter object. Count of the keys will be decreased with key count in Counter object.
  • If element is not present in the Counter, then new element with negative count, will be added from the given iterable or dictionary or Counter object.
elements are subtracted from an iterable or from another mapping (or counter)
Counter({'Python': 2, 'PowerBI': 1})      # Original Counter Object
Counter({'Python': 1, 'PowerBI': 0})      # Update (subtract) with list iterable
Counter({'Python': -1, 'PowerBI': -3})    # Update (subtract) with dictionary object
Counter({'Python': -3, 'PowerBI': -6})    # Update (subtract) with another Counter object

In this program, Counter object is updated (subtracted) multiple times with list, dictionary, or Counter object. Each time count value of the key decreased (subtract new value from previous value) with the new value from the iterable.

Counter Common Patterns

There are some common patterns which can be applicable with Counter object.

#counter common patterns
print("counter common patterns")

from collections import Counter
char_counter = Counter("shbytes")              # Create original Counter from string
print(char_counter)

print(sum(char_counter.values()))              # Get total sum of Counter values
print(list(char_counter))                      # Get Counter keys as list
print(set(char_counter))                       # Get Counter keys as set
print(dict(char_counter))                      # Get Counter elements as dictionary (key, value) item
print(char_counter.items())                    # Get Counter elements as list of (key, value) items
print(Counter(dict(char_counter.items())))     # Create Counter from (key, value) items list

Program Output

counter common patterns
Counter({'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1})
7
['s', 'h', 'b', 'y', 't', 'e']
{'b', 'e', 'h', 't', 'y', 's'}
{'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1}
dict_items([('s', 2), ('h', 1), ('b', 1), ('y', 1), ('t', 1), ('e', 1)])
Counter({'s': 2, 'h': 1, 'b': 1, 'y': 1, 't': 1, 'e': 1})

Counter remove zero or negative counts

Use +counter_object to remove zero or negative count elements from the Counter.

# +counter - remove zero and negative counts
print("+counter - remove zero and negative counts")

char1_counter = Counter(a=2,b=2,c=2)
char2_counter = Counter(c=2,d=1,e=1)

char1_counter.subtract(char2_counter)   # subtract Counter2 from Counter1
print(char1_counter)

print(+char1_counter)                   # remove zero or negative count elements

char1_counter.clear()                   # remove all elements
print(char1_counter)

Program Output

+counter - remove zero and negative counts
Counter({'a': 2, 'b': 2, 'c': 0, 'd': -1, 'e': -1})
Counter({'a': 2, 'b': 2})
Counter()

Arithmetic Operations – Counter Object

We can perform multiple arithmetic operations on Counter object. Some examples of arithmetic operations are:

  • Addcounter1[x] + counter2[x] => This results with new Counter object that will have all unique elements from both counters. Common elements count value will be added.
  • Subtractcounter1[x] - counter2[x] => This results with new Counter object that will have elements from the first counter, with positive count elements only. Zero or negative count elements will be removed.
  • Intersectioncounter1 & counter2 => This results with new Counter object. Only elements which are present in both intersecting Counters with minimum count value => min(c1[x], c2[x])
  • Unioncounter1 | counter2 => This results with new Counter object. Elements from both the counters will be kept. For common element element with maximum count value will be taken => max(c1[x], c2[x])
  • Unary addition for adding an empty counter => +char1_counter => keep only positive count elements.
  • Unary subtraction for subtracting from an empty counter => -char1_counter => keep only negative count elements.
from collections import Counter
char1_counter = Counter(a=2,b=2,c=2)
char2_counter = Counter(c=1,d=1,e=1)

# add two counters together: counter1[x] + counter2[x]
print("add two counters together: counter1[x] + counter2[x]")
add_char_counter = char1_counter + char2_counter
print(add_char_counter)

# subtract (keeping only positive counts): counter1[x] - counter2[x]
print("subtract (keeping only positive counts): counter1[x] - counter2[x]")
subtract_char_counter = char1_counter - char2_counter
print(subtract_char_counter)

# intersection: min(c1[x], c2[x]) - counter1 & counter2
print("intersection: min(c1[x], c2[x]) - counter1 & counter2")
intersect_char_counter = char1_counter & char2_counter
print(intersect_char_counter)

# union: max(c1[x], c2[x]) - counter1 | counter2
print("union: max(c1[x], c2[x]) - counter1 | counter2")
union_char_counter = char1_counter | char2_counter
print(union_char_counter)

char1_counter.subtract(char2_counter)
print(char1_counter)
# unary addition for adding an empty counter
print("unary addition for adding an empty counter")
print(+char1_counter)

#unary subtraction for subtracting from an empty counter
print("unary subtraction for subtracting from an empty counter")
print(-char1_counter)

Program Output

add two counters together: counter1[x] + counter2[x]
Counter({'c': 3, 'a': 2, 'b': 2, 'd': 1, 'e': 1})

subtract (keeping only positive counts): counter1[x] - counter2[x]
Counter({'a': 2, 'b': 2, 'c': 1})

intersection: min(c1[x], c2[x]) - counter1 & counter2
Counter({'c': 1})

union: max(c1[x], c2[x]) - counter1 | counter2
Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1, 'e': 1})

Counter({'a': 2, 'b': 2, 'c': 1, 'd': -1, 'e': -1})
unary addition for adding an empty counter
Counter({'a': 2, 'b': 2, 'c': 1})
unary subtraction for subtracting from an empty counter
Counter({'d': 1, 'e': 1})

Summary

In this article, we learned about Counter collection in Python. Following topics were discussed:

Code – Github Repository

All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.

Python Topics


Interview Questions & Answers

Q: Write a program to count the words in the given text?

  • In this program, we have used collections and re (Regular Expression) module. re module is used to create token for the given text.
  • We have created a Counter for the list of words and will get the count of each word.
from collections import Counter
import re   # Regular Expression module for tokenizer

text = "This test string is only for test. This test is only for test."
# Simple word tokenizer, list of words
words = re.findall(r'\w+', text.lower())
word_counts = Counter(words)
print(word_counts)
# Counter({'test': 4, 'this': 2, 'is': 2, 'only': 2, 'for': 2, 'string': 1})

Q: Find the duplicate numbers from the given list of numbers?

from collections import Counter

numbers_list = [14, 54, 68, 54, 79, 45, 68, 14]
item_counter = Counter(numbers_list)
duplicates = [number for number, count in item_counter.items() if count > 1]
print(duplicates)
# Duplicate numbers - [14, 54, 68]

Q: Check if the given pair of words is anagram or not?

Anagrams are the words, phrases, or names formed by rearranging the letters of another. e.g. cat & act are anagram words because they can be created by rearranging letters from each other.

To check for two phrases to anagram, we just to check if Counter of both are equal or not.

from collections import Counter

def check_anagrams(str_1, str_2):
    return Counter(str_1.replace(" ", "").lower()) == Counter(str_2.replace(" ", "").lower())

print(check_anagrams("listen", "silent"))    # True
print(check_anagrams("Hello", "World"))      # False

Q: Create a histogram for the frequency of numbers given in the list of numbers?

We will use matplotlib package of Python, to plot the histogram.

from collections import Counter
import matplotlib.pyplot as plt

numbers_list = [14, 54, 68, 54, 34, 23, 79, 45, 68, 14, 54, 14, 54]
numbers_counter = Counter(numbers_list)

plt.bar(numbers_counter.keys(), numbers_counter.values())
plt.xlabel('Numbers')
plt.ylabel('Count')
plt.title('Numbers Histogram')
plt.show()

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *