Python
dictionary
lists
data structures
programming tutorial

Python creating a dictionary of lists

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

A dictionary of lists maps each key to a list of values, making it the go-to structure for grouping related items. The main challenge is handling the first value for a new key — you need to create the list before appending. Python provides several clean approaches: defaultdict(list), dict.setdefault(), and manual initialization. Each avoids the common KeyError trap.

The Problem: KeyError on First Append

python
groups = {}
groups["fruits"].append("apple")
# KeyError: 'fruits'

The key "fruits" does not exist yet, so there is no list to append to. You must create the list first.

collections.defaultdict automatically creates an empty list for any new key:

python
1from collections import defaultdict
2
3groups = defaultdict(list)
4
5groups["fruits"].append("apple")
6groups["fruits"].append("banana")
7groups["vegetables"].append("carrot")
8
9print(dict(groups))
10# {'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}

When you access groups["fruits"] and it does not exist, defaultdict calls list() to create an empty list, stores it, and returns it — all in one step.

Method 2: dict.setdefault()

setdefault(key, default) returns the existing value or sets and returns the default:

python
1groups = {}
2
3groups.setdefault("fruits", []).append("apple")
4groups.setdefault("fruits", []).append("banana")
5groups.setdefault("vegetables", []).append("carrot")
6
7print(groups)
8# {'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}

On the first call, setdefault creates the key with an empty list. On subsequent calls, it returns the existing list without replacing it.

Method 3: Manual Check

python
1groups = {}
2
3key = "fruits"
4if key not in groups:
5    groups[key] = []
6groups[key].append("apple")

This is explicit but verbose. Prefer defaultdict or setdefault for cleaner code.

Method 4: Dictionary Comprehension

When you already have your data, build the dict-of-lists in one expression:

python
1# Group words by their first letter
2words = ["apple", "avocado", "banana", "blueberry", "cherry"]
3
4groups = {}
5for word in words:
6    groups.setdefault(word[0], []).append(word)
7
8print(groups)
9# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}

Method 5: Using itertools.groupby

For data that is already sorted by the grouping key:

python
1from itertools import groupby
2
3data = [("fruit", "apple"), ("fruit", "banana"),
4        ("veggie", "carrot"), ("veggie", "pea")]
5
6groups = {k: [v for _, v in g] for k, g in groupby(data, key=lambda x: x[0])}
7print(groups)
8# {'fruit': ['apple', 'banana'], 'veggie': ['carrot', 'pea']}

groupby requires sorted input — consecutive items with the same key are grouped together.

Real-World Example: Grouping Records

python
1from collections import defaultdict
2
3students = [
4    {"name": "Alice", "grade": "A"},
5    {"name": "Bob", "grade": "B"},
6    {"name": "Charlie", "grade": "A"},
7    {"name": "Diana", "grade": "B"},
8    {"name": "Eve", "grade": "A"},
9]
10
11by_grade = defaultdict(list)
12for student in students:
13    by_grade[student["grade"]].append(student["name"])
14
15print(dict(by_grade))
16# {'A': ['Alice', 'Charlie', 'Eve'], 'B': ['Bob', 'Diana']}

Initializing with Known Keys

python
1# Pre-populate all keys with empty lists
2categories = ["fruits", "vegetables", "grains"]
3groups = {cat: [] for cat in categories}
4
5groups["fruits"].append("apple")
6groups["vegetables"].append("carrot")
7
8print(groups)
9# {'fruits': ['apple'], 'vegetables': ['carrot'], 'grains': []}

Nested Dictionaries of Lists

python
1from collections import defaultdict
2
3# Two-level grouping
4sales = defaultdict(lambda: defaultdict(list))
5
6sales["2025"]["Q1"].append(1000)
7sales["2025"]["Q2"].append(1500)
8sales["2025"]["Q1"].append(1200)
9
10print(dict(sales["2025"]))
11# {'Q1': [1000, 1200], 'Q2': [1500]}

Converting to and from Other Formats

python
1from collections import defaultdict
2
3# From list of tuples
4pairs = [("a", 1), ("b", 2), ("a", 3), ("b", 4), ("a", 5)]
5d = defaultdict(list)
6for k, v in pairs:
7    d[k].append(v)
8
9print(dict(d))  # {'a': [1, 3, 5], 'b': [2, 4]}
10
11# Back to list of tuples
12flat = [(k, v) for k, vals in d.items() for v in vals]
13print(flat)  # [('a', 1), ('a', 3), ('a', 5), ('b', 2), ('b', 4)]

Common Pitfalls

  • Mutable default argument trap: dict.fromkeys(keys, []) makes all keys share the SAME list. d["a"].append(1) modifies every key. Use a comprehension: {k: [] for k in keys}.
  • defaultdict with wrong factory: defaultdict(list) creates lists. defaultdict([]) raises TypeError because [] is not callable. The argument must be a callable like list, set, or int.
  • Forgetting groupby needs sorted input: itertools.groupby only groups consecutive matching elements. Sort the data first with sorted(data, key=...).
  • JSON serialization: json.dumps(defaultdict(list)) works, but the result loses the default factory. Convert to a regular dict first with dict(d) if you need to preserve the exact type.
  • Checking membership: key in defaultdict does NOT create the key. Only accessing d[key] triggers the default factory. Use key in d safely for existence checks.

Summary

  • Use defaultdict(list) for the cleanest auto-initializing dict-of-lists
  • Use dict.setdefault(key, []).append(value) when you want a plain dict
  • Never use dict.fromkeys(keys, []) — all keys share the same list
  • Use dictionary comprehensions {k: [] for k in keys} for pre-initialized dicts
  • itertools.groupby works for already-sorted data
  • Convert defaultdict to dict() before serializing to JSON

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.