I’m currently going over Python’s collection module exercises on HackerRank.

This module offers a range of data-structures and algorithms that can enhance the performance and functionality of your Python programs.

What I’ve learned so far is that when I am in need of some specialized data-structure, I should take a look into collections module.

Python’s collection module offers:

Counter

The Counter class within the collections module provides an efficient way to count the occurrence of elements in a collection. It takes an iterable as input and returns a dictionary-like object where elements are keys and their counts are the corresponding values.

With Counter, you can easily perform tasks such as finding the most common elements, subtracting counts, and merging counts from multiple counters.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from collections import Counter

# Count the occurrence of elements in a list
my_list = [1, 2, 3, 2, 1, 3, 4, 5, 1, 2]
counter = Counter(my_list)
print(counter)  # Output: Counter({1: 3, 2: 3, 3: 2, 4: 1, 5: 1})

# Get the 2 most common elements
most_common = counter.most_common(2)
print(most_common)  # Output: [(1, 3), (2, 3)]

Defaultdict

The defaultdict class is a subclass of the built-in dict class, offering a default value for missing keys. It simplifies the process of handling missing keys by assigning a default value automatically when accessing a non-existent key.

Defaultdict is particularly useful when working with nested dictionaries or creating complex data structures.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from collections import defaultdict

# Create a defaultdict with default value 0
my_dict = defaultdict(int)
my_dict['a'] += 1
my_dict['b'] += 2
print(my_dict)  # Output: defaultdict(<class 'int'>, {'a': 1, 'b': 2})

# Create a defaultdict with default value list
my_dict = defaultdict(list)
my_dict['colors'].append('red')
my_dict['colors'].append('blue')
print(my_dict)  # Output: defaultdict(<class 'list'>, {'colors': ['red', 'blue']})

Deque

The deque class provides a double-ended queue, allowing efficient appending and popping of elements from both ends. Unlike regular lists, deques are optimized for fast operations at both ends, making them an excellent choice for implementing queues, stacks, and other data structures where efficient insertion and deletion at both ends are crucial.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from collections import deque

# Create a deque
my_deque = deque([1, 2, 3])
print(my_deque)  # Output: deque([1, 2, 3])

# Append and pop elements from both ends
my_deque.append(4)
my_deque.appendleft(0)
print(my_deque)  # Output: deque([0, 1, 2, 3, 4])

popped_element = my_deque.pop()
print(popped_element)  # Output: 4

popped_element = my_deque.popleft()
print(popped_element)  # Output: 0

Namedtuple

Named tuples are an extension of tuples, providing named fields that can be accessed using dot notation. They offer a convenient way to define lightweight, immutable data structures. Named tuples are especially useful when you have a collection of objects that share a common structure but don’t require the overhead of a full-fledged class.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from collections import namedtuple

# Define a named tuple for a Point
Point = namedtuple('Point', ['x', 'y'])

# Create an instance of Point
p = Point(2, 3)
print(p.x, p.y)  # Output: 2 3

# Access fields using dot notation
p = Point(x=4, y=5)
print(p.x, p.y)  # Output: 4 5

OrderedDict

While dictionaries in Python 3.7 and above are ordered by default, the OrderedDict class in the collections module ensures that the order of insertion is preserved. This can be valuable when you need to maintain a specific order of elements or create a cache that discards the least recently used items when it reaches a certain size.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from collections import OrderedDict

# Create an ordered dictionary
my_dict = OrderedDict()

# Add elements with specific order
my_dict['b'] = 2
my_dict['a'] = 1
my_dict['c'] = 3
print(my_dict)  # Output: OrderedDict([('b', 2), ('a', 1), ('c', 3)])

ChainMap

The ChainMap class allows you to combine multiple dictionaries or other mappings into a single, logical view. It creates a list of dictionaries, searching for a key sequentially across all dictionaries until a match is found. ChainMap provides a convenient way to work with multiple dictionaries as a single entity without merging them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from collections import ChainMap

# Create dictionaries
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

# Create a ChainMap
chain_map = ChainMap(dict1, dict2)

# Access elements
print(chain_map['a'])  # Output: 1
print(chain_map['b'])  # Output: 2 (searches dict1 first)
print(chain_map['c'])  # Output: 4

On these I have completed few exercises. One that I find very useful is DefaultDict as it creates a default value for a key and therefore avoids many possible problems. There are few more containers offered by collections module: UserDict, UserList, UserString.