How to Aggregate Multiple Inputs in Python Dictionaries
Aggregating multiple dictionaries is a frequent task in Python, whether you are merging configuration files, combining datasets, or summing up counters. Depending on your goal, "aggregation" might mean a simple merge (overwriting duplicates) or a complex combination (summing values or recursive merging).
This guide covers the most efficient techniques to aggregate dictionaries, ranging from standard merging operators to deep recursive updates.
Standard Merging (Last Value Wins)
If your goal is to combine dictionaries where keys from later dictionaries overwrite earlier ones, Python provides several built-in methods.
The Merge Operator | (Python 3.9+)
The cleanest syntax for merging dictionaries is the union operator |.
default_settings = {"theme": "light", "notifications": True}
user_settings = {"theme": "dark"}
# ✅ Solution: Using the | operator
config = default_settings | user_settings
print(f"Merged Config: {config}")
Output:
Merged Config: {'theme': 'dark', 'notifications': True}
Unpacking ** (Python 3.5+)
For older Python versions, dictionary unpacking is the standard approach.
dict_a = {"a": 1, "b": 2}
dict_b = {"b": 3, "c": 4}
# ✅ Solution: Unpacking into a new dictionary
# Note: 'b' becomes 3 because dict_b comes last
merged = {**dict_a, **dict_b}
print(f"Merged: {merged}")
Output:
Merged: {'a': 1, 'b': 3, 'c': 4}
Both | and ** create a new dictionary. To modify a dictionary in-place, use dict_a.update(dict_b).
Aggregating Values (Summing Duplicates)
A common issue with standard merging is that it replaces values. If you want to aggregate values (e.g., sum up scores or inventory counts) for shared keys, you need a different approach.
Using collections.Counter
The Counter class is the most efficient tool for summing integer values across dictionaries.
from collections import Counter
sales_q1 = {"apples": 100, "bananas": 50}
sales_q2 = {"apples": 200, "oranges": 30}
# ⛔️ Standard merge overwrites data
# print(sales_q1 | sales_q2) -> {'apples': 200, ...} (Wrong for totals)
# ✅ Solution: Use Counter for arithmetic aggregation
total_sales = Counter(sales_q1) + Counter(sales_q2)
print(f"Total Sales: {dict(total_sales)}")
Output:
Total Sales: {'apples': 300, 'bananas': 50, 'oranges': 30}
Using Dictionary Comprehension (Custom Logic)
If you need non-numeric aggregation (like concatenating lists or strings), use a set of all keys and a comprehension.
d1 = {"team": "Alpha", "tags": ["red"]}
d2 = {"team": "Beta", "tags": ["blue"]}
# ✅ Solution: Aggregate 'tags' into a combined list
all_keys = set(d1) | set(d2)
aggregated = {
k: d1.get(k, []) + d2.get(k, [])
for k in all_keys
if k == "tags" # Logic specific to 'tags'
}
print(aggregated)
Output:
{'tags': ['red', 'blue']}
Deep Merging (Recursive Aggregation)
When working with nested dictionaries (like JSON configurations), a shallow merge (| or update) will completely replace nested dictionaries rather than merging their contents. You need a recursive function.
def deep_merge(dict1, dict2):
"""
Recursively merges dict2 into dict1.
"""
result = dict1.copy()
for key, value in dict2.items():
# If both keys contain dictionaries, recurse
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = deep_merge(result[key], value)
else:
result[key] = value
return result
config_base = {
"server": {
"host": "localhost",
"port": 8080
}
}
config_override = {
"server": {
"port": 9000 # Only override port, keep host
}
}
# ⛔️ Standard merge would lose 'host'
# print(config_base | config_override)
# -> {'server': {'port': 9000}}
# ✅ Solution: Recursive Deep Merge
full_config = deep_merge(config_base, config_override)
print(f"Deep Merged: {full_config}")
Output:
Deep Merged: {'server': {'host': 'localhost', 'port': 9000}}
Aggregating a List of Dictionaries
Often data comes as a list of dictionaries, and you need to combine them all into a single result.
Using functools.reduce
reduce applies a function cumulatively to items in a sequence.
from functools import reduce
data = [
{"a": 1, "b": 2},
{"b": 3, "c": 4},
{"d": 5}
]
def merge_logic(acc, curr):
return {**acc, **curr} # Simple merge (last wins)
# ✅ Solution: Reduce list of dicts to one dict
final_dict = reduce(merge_logic, data)
print(f"Reduced Dict: {final_dict}")
Output:
Reduced Dict: {'a': 1, 'b': 3, 'c': 4, 'd': 5}
For summing values across a list of dictionaries, you can pass Counter objects to reduce with the + operator.
Conclusion
To aggregate dictionaries effectively in Python:
- Use
|(Python 3.9+) or**unpacking for simple merging where the last value overwrites previous ones. - Use
collections.Counterif you need to perform arithmetic aggregation (summing numbers) on shared keys. - Use a recursive function if you need to merge nested structures (deep merge) without losing data in sub-dictionaries.