Skip to Content
Course content

228: Collections Module: defaultdict

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're sorting a massive pile of physical mail into folders. Every time you pick up a letter, you look at the recipient's name. With a standard dictionary approach, your process looks like this: "Is there already a folder for 'John Doe'? No? Okay, I need to stop what I'm doing, go to the supply cabinet, grab a brand new empty folder, write 'John Doe' on the tab, put it on the desk, and then put the letter inside."

It's tedious. You're spending half your time managing the folders rather than actually sorting the mail.

A defaultdict is like having a magic desk. Whenever you try to put a letter into a folder that doesn't exist, the desk instantly manifests a brand new, empty folder for that person the millisecond you reach for it. You don't have to check if it's there; you just act as if it always has been.

Stopping the KeyError Cycle

If you've been using standard dictionaries to group data, you've probably written this pattern a hundred times:


# The old, clunky way
user_groups = {}
users = [('admin', 'Alice'), ('editor', 'Bob'), ('admin', 'Charlie')]

for role, name in users:
    if role not in user_groups:
        user_groups[role] = []
    user_groups[role].append(name)

I'll be honest: that if role not in user_groups check is noise. It doesn't describe what your code is doing; it just manages a limitation of the dictionary. This is exactly where defaultdict from the collections module shines. It lets you skip the check entirely.


from collections import defaultdict

# We tell defaultdict that if a key is missing, it should call list() to create a value
user_groups = defaultdict(list)
users = [('admin', 'Alice'), ('editor', 'Bob'), ('admin', 'Charlie')]

for role, name in users:
    # No if-statement needed. If 'admin' isn't there, Python creates [] automatically.
    user_groups[role].append(name)

The "Factory" is the Key

Notice that I passed list into defaultdict(). I didn't pass an empty list []; I passed the function (or type) that creates a list. This is called a "default factory."

You can use different factories depending on what you're trying to achieve. I've found these three to be the most useful in real-world projects:

  • defaultdict(list): Great for grouping items (like the example above).
  • defaultdict(int): Perfect for counting. Since int() returns 0, you can start incrementing immediately: counts[item] += 1.
  • defaultdict(set): Use this when you want to group items but ensure there are no duplicates in each group.

One thing to keep in mind: defaultdict creates the entry the moment you access it. If you try to print a key that doesn't exist, defaultdict won't throw an error—it will simply create that key with the default value and return it. This is usually a feature, but it can occasionally lead to "bloated" dictionaries if you're checking for keys that you don't actually intend to use.




📋 Practical Task

The Social Media Hashtag Aggregator

You are building a tool to analyze trending topics. You have a list of posts, where each post is a string containing text and hashtags (words starting with #). Your goal is to create a mapping where every hashtag is a key, and the value is a set of unique usernames who used that hashtag.

Your Task:

  1. Import defaultdict from collections.
  2. Create a defaultdict using a factory that ensures the values are sets.
  3. Process the following data:
    
    posts = [
        {"user": "alice", "text": "Loving the #python life! #coding"},
        {"user": "bob", "text": "Just started learning #python. So cool!"},
        {"user": "charlie", "text": "Check out this #coding tip! #python"},
        {"user": "alice", "text": "Another #python post because I love it!"},
    ]
        
  4. Iterate through the posts, extract the hashtags, and add the user to the corresponding hashtag set.
  5. Print the final dictionary.

Hint: You can use post["text"].split() to get the words and a simple if word.startswith("#") to identify the hashtags.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.