Hello! Welcome to the fifth lesson in our module, "Python Tools for Competitive Programming."
In our last lesson, we mastered collections.Counter and saw how it provides a specialized, efficient way to handle frequency counting. A key feature we noted was how Counter gracefully handles missing keys by returning 0, avoiding the common KeyError.
Today, we'll explore another powerful tool from the collections module that expands on this idea: collections.defaultdict. This lesson's goal is to learn how to use defaultdict to simplify aggregation and grouping tasks. Grouping data is a fundamental step in solving many competitive programming problems, and defaultdict makes this process incredibly clean and efficient.
1. The Challenge of Grouping with Standard Dictionaries
Imagine you have a list of words and you want to group them by their starting letter. Using a standard Python dictionary, your code might look something like this:
words = ["apple", "ant", "ball", "bat", "cat"]
grouped_words = {}
for word in words:
first_letter = word[0]
if first_letter not in grouped_words:
# If the key doesn't exist, we must first create an empty list
grouped_words[first_letter] = []
# Now we can safely append the word
grouped_words[first_letter].append(word)
print(grouped_words)
# Output: {'a': ['apple', 'ant'], 'b': ['ball', 'bat'], 'c': ['cat']}
This code works perfectly fine, but the if/else block to check for the key's existence is a piece of "boilerplate" that you'll find yourself writing over and over again. It clutters the logic. What if the dictionary could automatically create that empty list for us the first time we encounter a new key? That's exactly what defaultdict does.
The following video demonstrates this exact problem, first showing the if-else approach with a regular dictionary before introducing defaultdict as a more elegant solution.
DefaultDict Tutorial | HackerRank | Collections | Python Programming | Coding
Watch this segment from the "DefaultDict Tutorial" video by Coding Cart. It clearly illustrates the boilerplate code needed when using a regular dictionary for grouping and sets the stage for why defaultdict is so useful.
Watch from 05:37 to 13:52. The video walks through an experiment of grouping indices using a standard dictionary, demonstrating the need for an if-else check to handle new keys.
2. Introducing collections.defaultdict
A defaultdict is a subclass of the standard dict. It's special because it allows you to specify a function that will be used to provide a default value for a key that does not exist.
To use it, you import it from the collections module and create it by passing a "default factory" function.
from collections import defaultdict
# The default_factory is 'list'. When a new key is accessed, list() is called to create an empty list.
grouped_words = defaultdict(list)
words = ["apple", "ant", "ball", "bat", "cat"]
for word in words:
first_letter = word[0]
# No if-check needed! If the key doesn't exist, defaultdict creates an empty list and then appends.
grouped_words[first_letter].append(word)
print(grouped_words)
# Output: defaultdict(<class 'list'>, {'a': ['apple', 'ant'], 'b': ['ball', 'bat'], 'c': ['cat']})
Notice how much cleaner this is. The if first_letter not in grouped_words: logic is gone. The defaultdict handles it automatically.

The following article provides a concise guide to how defaultdict works and its primary use cases.
Mastering Python's defaultdict: A Comprehensive Guide
Let's read a section from "Mastering Python's defaultdict: A Comprehensive Guide" by AlgoCademy. It will formalize your understanding of how defaultdict works and its common applications.
Read sections 1 through 4, titled "Introduction to defaultdict," "How defaultdict Works," "Creating and Using defaultdict," and "Common Use Cases for defaultdict." Pay close attention to the default_factory concept and the examples for grouping items.
3. Common defaultdict Factories for Competitive Programming
The "factory" you provide to defaultdict determines the default value for new keys. Here are the most common ones you'll use:
defaultdict(list): For grouping items into lists. This is the most frequent use case.defaultdict(int): For counting items. When a new key is accessed, it gets a default value ofint(), which is0. This makes it behave similarly tocollections.Counter.defaultdict(set): For grouping unique items. This is very useful when building graph representations (e.g., an adjacency list) or when you need to avoid duplicate entries in your groups.
The following video provides a clear, visual explanation of these different factories in action.
Advanced Dictionaries: defaultdict in Python
The video "Advanced Dictionaries: defaultdict in Python" by NeuralNine gives a great overview of initializing defaultdict with different types.
Watch from 01:57 to 07:09. This part covers using int for counting, list for grouping words by their first letter, and even using it to aggregate data from a list of tuples.

Test your understanding!
You are given a list of tuples, where each tuple contains a student's name and their score on a test.scores = [('Alice', 88), ('Bob', 92), ('Alice', 95), ('Charlie', 78), ('Bob', 85)]
Using defaultdict, write a few lines of code to create a dictionary that groups each student's scores into a list. The output should be:{'Alice': [88, 95], 'Bob': [92, 85], 'Charlie': [78]}
Show answer
from collections import defaultdict
scores = [('Alice', 88), ('Bob', 92), ('Alice', 95), ('Charlie', 78), ('Bob', 85)]
score_groups = defaultdict(list)
for name, score in scores:
score_groups[name].append(score)
print(dict(score_groups)) # Converted to a regular dict for cleaner printing
This demonstrates the primary power of defaultdict(list). Without needing to check if a student's name is already a key, we can directly .append() their score.
4. Application: Solving a HackerRank Problem
Now let's bring it all together and see how defaultdict shines in a typical competitive programming problem. We'll revisit the video from the start of the lesson, this time focusing on the full solution.
Problem Context: You are given two groups of words, A and B. For each word in group B, you need to find all the 1-based indices where it appears in group A. If a word from B doesn't appear in A, you should report -1.
This is a classic grouping problem: you need to group the indices of each word in group A.
DefaultDict Tutorial | HackerRank | Collections | Python Programming | Coding
Let's watch the complete solution to the HackerRank problem in the "DefaultDict Tutorial" video. This will show you the defaultdict solution side-by-side with the standard dictionary approach, highlighting its conciseness.
Watch from 13:52 to the end (22:16). Pay close attention to how the if-else block is completely removed in the defaultdict version of the code, and how this simplifies the logic for solving the problem.
This walkthrough is a perfect example of how choosing the right data structure from the collections module not only makes your code cleaner but also easier to reason about, which is critical under the time pressure of a competition.
Conclusion
You've now learned about collections.defaultdict, a powerful tool for simplifying code that groups or aggregates data. By handling the automatic creation of default values for missing keys, it removes boilerplate and lets you focus on the core logic of your algorithm.
Key Takeaways:
defaultdictis a dictionary subclass that provides a default value for missing keys, preventingKeyError.- It is initialized with a
default_factory(e.g.,list,int,set) that is called to create the default value. defaultdict(list)is the go-to solution for grouping items into lists.defaultdict(int)provides a simple way to implement counters.- Using
defaultdictleads to cleaner, more readable, and often more efficient code in aggregation tasks.
Up Next: In our final lesson for this module, we will explore Python's built-in map and filter functions. These are powerful tools from functional programming that allow you to transform and select data from iterables in a very concise way.