Python - Dictionary Comprehension
• Dictionary comprehensions provide a concise syntax for creating dictionaries from iterables, reducing multi-line loops to single expressions while maintaining readability
Key Insights
• Dictionary comprehensions provide a concise syntax for creating dictionaries from iterables, reducing multi-line loops to single expressions while maintaining readability • They support conditional logic (if/else), nested iterations, and can transform both keys and values simultaneously, making them ideal for data transformation tasks • Performance benchmarks show dictionary comprehensions are 10-30% faster than traditional loops due to optimized C-level implementation in CPython
Basic Syntax and Structure
Dictionary comprehensions follow the pattern {key_expression: value_expression for item in iterable}. This creates a new dictionary by iterating through an iterable and applying expressions to generate key-value pairs.
# Traditional approach
squares = {}
for x in range(5):
squares[x] = x ** 2
# Dictionary comprehension
squares = {x: x ** 2 for x in range(5)}
# Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
The comprehension evaluates the key expression first, then the value expression for each iteration. Both expressions have access to the iteration variable.
# Creating a dictionary from two lists
keys = ['name', 'age', 'city']
values = ['Alice', 30, 'NYC']
user_data = {k: v for k, v in zip(keys, values)}
# Output: {'name': 'Alice', 'age': 30, 'city': 'NYC'}
Conditional Filtering
Add conditional logic with if clauses to filter which items become dictionary entries. The condition is evaluated before creating the key-value pair.
# Filter even numbers only
even_squares = {x: x ** 2 for x in range(10) if x % 2 == 0}
# Output: {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# Filter based on value conditions
prices = {'apple': 0.5, 'banana': 0.3, 'orange': 0.8, 'grape': 1.2}
expensive_items = {item: price for item, price in prices.items() if price > 0.5}
# Output: {'orange': 0.8, 'grape': 1.2}
For conditional value assignment (if-else), place the condition within the value expression:
# Categorize numbers as even or odd
number_types = {x: 'even' if x % 2 == 0 else 'odd' for x in range(5)}
# Output: {0: 'even', 1: 'odd', 2: 'even', 3: 'odd', 4: 'even'}
# Apply discount to expensive items
adjusted_prices = {
item: price * 0.9 if price > 1.0 else price
for item, price in prices.items()
}
Transforming Existing Dictionaries
Dictionary comprehensions excel at transforming existing dictionaries by modifying keys, values, or both.
# Convert keys to uppercase
original = {'name': 'Bob', 'age': 25, 'city': 'LA'}
uppercase_keys = {k.upper(): v for k, v in original.items()}
# Output: {'NAME': 'Bob', 'AGE': 25, 'CITY': 'LA'}
# Apply function to all values
def celsius_to_fahrenheit(c):
return (c * 9/5) + 32
temps_c = {'morning': 15, 'noon': 22, 'evening': 18}
temps_f = {time: celsius_to_fahrenheit(temp) for time, temp in temps_c.items()}
# Output: {'morning': 59.0, 'noon': 71.6, 'evening': 64.4}
Swap keys and values when values are unique and hashable:
user_ids = {'alice': 101, 'bob': 102, 'charlie': 103}
id_to_user = {v: k for k, v in user_ids.items()}
# Output: {101: 'alice', 102: 'bob', 103: 'charlie'}
Nested Dictionary Comprehensions
Nest comprehensions to create dictionaries of dictionaries or process nested structures.
# Create multiplication table
multiplication_table = {
i: {j: i * j for j in range(1, 6)}
for i in range(1, 6)
}
# Output: {1: {1: 1, 2: 2, 3: 3, 4: 4, 5: 5},
# 2: {1: 2, 2: 4, 3: 6, 4: 8, 5: 10}, ...}
# Flatten nested dictionary
nested = {
'user1': {'name': 'Alice', 'age': 30},
'user2': {'name': 'Bob', 'age': 25}
}
flattened = {
f"{user_id}_{key}": value
for user_id, user_data in nested.items()
for key, value in user_data.items()
}
# Output: {'user1_name': 'Alice', 'user1_age': 30,
# 'user2_name': 'Bob', 'user2_age': 25}
Practical Data Processing Examples
Dictionary comprehensions shine in real-world data transformation scenarios.
# Group items by category
transactions = [
{'item': 'apple', 'category': 'fruit', 'amount': 5},
{'item': 'carrot', 'category': 'vegetable', 'amount': 3},
{'item': 'banana', 'category': 'fruit', 'amount': 7},
]
category_totals = {
category: sum(t['amount'] for t in transactions if t['category'] == category)
for category in set(t['category'] for t in transactions)
}
# Output: {'fruit': 12, 'vegetable': 3}
Parse configuration strings into structured data:
config_lines = [
'database=postgres',
'host=localhost',
'port=5432',
'debug=true'
]
config = {
line.split('=')[0]: line.split('=')[1]
for line in config_lines
}
# Output: {'database': 'postgres', 'host': 'localhost',
# 'port': '5432', 'debug': 'true'}
Build lookup tables for performance optimization:
# Create index for fast lookups
users = [
{'id': 1, 'name': 'Alice', 'email': 'alice@example.com'},
{'id': 2, 'name': 'Bob', 'email': 'bob@example.com'},
]
user_by_id = {user['id']: user for user in users}
user_by_email = {user['email']: user for user in users}
# Fast O(1) lookup instead of O(n) iteration
alice = user_by_email['alice@example.com']
Handling Complex Key-Value Expressions
Use parentheses and function calls for complex transformations:
import json
# Parse JSON strings as values
raw_data = {
'user1': '{"name": "Alice", "score": 95}',
'user2': '{"name": "Bob", "score": 87}'
}
parsed_data = {k: json.loads(v) for k, v in raw_data.items()}
# Complex key generation
words = ['hello', 'world', 'python']
word_analysis = {
word: {
'length': len(word),
'vowels': sum(1 for c in word if c in 'aeiou'),
'uppercase': word.upper()
}
for word in words
}
Performance Considerations
Dictionary comprehensions outperform equivalent loops due to optimized implementation:
import timeit
# Benchmark comparison
def using_loop():
result = {}
for i in range(1000):
result[i] = i ** 2
return result
def using_comprehension():
return {i: i ** 2 for i in range(1000)}
loop_time = timeit.timeit(using_loop, number=10000)
comp_time = timeit.timeit(using_comprehension, number=10000)
print(f"Loop: {loop_time:.4f}s")
print(f"Comprehension: {comp_time:.4f}s")
print(f"Speedup: {loop_time/comp_time:.2f}x")
# Typical output shows 1.2-1.3x speedup
However, prioritize readability over micro-optimizations. For complex logic spanning multiple lines, traditional loops with clear variable names often improve maintainability:
# Avoid overly complex comprehensions
# BAD: Hard to read
result = {k: v for k, v in data.items() if v > threshold and k.startswith('x') if process(v)}
# GOOD: Clear intent
result = {}
for key, value in data.items():
if value > threshold and key.startswith('x'):
processed_value = process(value)
if processed_value:
result[key] = processed_value
Dictionary comprehensions are a powerful tool for concise data transformation. Use them when the logic fits naturally in a single expression, and fall back to traditional loops when complexity demands clarity.