Python - Convert List to Dictionary
The most straightforward conversion occurs when you have a list of tuples, where each tuple contains a key-value pair. The `dict()` constructor handles this natively.
Key Insights
- Python offers multiple built-in methods to convert lists to dictionaries, including
dict(),zip(), and dictionary comprehensions, each suited for different data structures - The conversion strategy depends on your list structure: paired tuples, separate key-value lists, or lists requiring index-based or computed keys
- Understanding these patterns prevents common pitfalls like duplicate keys, mismatched list lengths, and type errors during conversion
Converting List of Tuples to Dictionary
The most straightforward conversion occurs when you have a list of tuples, where each tuple contains a key-value pair. The dict() constructor handles this natively.
# List of tuples (key, value)
pairs = [('name', 'Alice'), ('age', 30), ('city', 'Boston')]
result = dict(pairs)
print(result)
# Output: {'name': 'Alice', 'age': 30, 'city': 'Boston'}
# Works with any iterable of pairs
nested_list = [['id', 101], ['status', 'active'], ['score', 95.5]]
result = dict(nested_list)
print(result)
# Output: {'id': 101, 'status': 'active', 'score': 95.5}
This method fails if tuples don’t contain exactly two elements. Handle variable-length tuples explicitly:
# Handling tuples with more than 2 elements
data = [('key1', 'val1', 'extra'), ('key2', 'val2')]
# Take only first two elements
result = dict((item[0], item[1]) for item in data)
print(result)
# Output: {'key1': 'val1', 'key2': 'val2'}
Using zip() for Parallel Lists
When you have separate lists for keys and values, zip() combines them element-wise before conversion.
keys = ['product', 'quantity', 'price']
values = ['Laptop', 5, 999.99]
result = dict(zip(keys, values))
print(result)
# Output: {'product': 'Laptop', 'quantity': 5, 'price': 999.99}
Handle mismatched list lengths to avoid silent data loss:
keys = ['a', 'b', 'c', 'd']
values = [1, 2, 3]
# zip stops at shortest list
result = dict(zip(keys, values))
print(result)
# Output: {'a': 1, 'b': 2, 'c': 3} # 'd' is lost
# Detect length mismatch
if len(keys) != len(values):
raise ValueError(f"Length mismatch: {len(keys)} keys, {len(values)} values")
# Or use itertools.zip_longest for padding
from itertools import zip_longest
result = dict(zip_longest(keys, values, fillvalue=None))
print(result)
# Output: {'a': 1, 'b': 2, 'c': 3, 'd': None}
Dictionary Comprehensions for Transformations
Dictionary comprehensions provide the most flexibility when you need to transform data during conversion.
# Using list indices as keys
items = ['apple', 'banana', 'cherry']
result = {i: item for i, item in enumerate(items)}
print(result)
# Output: {0: 'apple', 1: 'banana', 2: 'cherry'}
# Custom key generation
result = {item.upper(): len(item) for item in items}
print(result)
# Output: {'APPLE': 5, 'BANANA': 6, 'CHERRY': 6}
# Filtering during conversion
numbers = [1, 2, 3, 4, 5, 6]
result = {f'num_{n}': n**2 for n in numbers if n % 2 == 0}
print(result)
# Output: {'num_2': 4, 'num_4': 16, 'num_6': 36}
Apply transformations to both keys and values:
# List of user data
users = [
['Alice', 'alice@example.com'],
['Bob', 'bob@example.com'],
['Charlie', 'charlie@example.com']
]
# Extract username from email and normalize name
result = {
email.split('@')[0]: name.lower()
for name, email in users
}
print(result)
# Output: {'alice': 'alice', 'bob': 'bob', 'charlie': 'charlie'}
Handling Duplicate Keys
Duplicate keys in your source list will cause later values to overwrite earlier ones. Handle this explicitly based on your requirements.
pairs = [('a', 1), ('b', 2), ('a', 3), ('c', 4)]
# Default behavior: last value wins
result = dict(pairs)
print(result)
# Output: {'a': 3, 'b': 2, 'c': 4}
# Keep first occurrence
result = {}
for key, value in pairs:
if key not in result:
result[key] = value
print(result)
# Output: {'a': 1, 'b': 2, 'c': 4}
# Collect all values for duplicate keys
from collections import defaultdict
result = defaultdict(list)
for key, value in pairs:
result[key].append(value)
result = dict(result)
print(result)
# Output: {'a': [1, 3], 'b': [2], 'c': [4]}
Converting Nested Lists
Complex nested structures require custom logic to determine key-value relationships.
# List of dictionaries to single dictionary
data = [
{'id': 1, 'name': 'Product A'},
{'id': 2, 'name': 'Product B'},
{'id': 3, 'name': 'Product C'}
]
# Use specific field as key
result = {item['id']: item['name'] for item in data}
print(result)
# Output: {1: 'Product A', 2: 'Product B', 3: 'Product C'}
# Keep entire object as value
result = {item['id']: item for item in data}
print(result[1])
# Output: {'id': 1, 'name': 'Product A'}
Flatten nested lists with multiple levels:
# Nested list structure
nested = [
['category1', [('item1', 10), ('item2', 20)]],
['category2', [('item3', 30), ('item4', 40)]]
]
# Flatten to single dictionary
result = {
item: value
for category, items in nested
for item, value in items
}
print(result)
# Output: {'item1': 10, 'item2': 20, 'item3': 30, 'item4': 40}
# Preserve category structure
result = {
category: dict(items)
for category, items in nested
}
print(result)
# Output: {'category1': {'item1': 10, 'item2': 20},
# 'category2': {'item3': 30, 'item4': 40}}
Using fromkeys() for Default Values
The dict.fromkeys() method creates a dictionary from a list of keys with a default value.
keys = ['status', 'count', 'active']
# All keys get same default value
result = dict.fromkeys(keys, 0)
print(result)
# Output: {'status': 0, 'count': 0, 'active': 0}
# Default is None if not specified
result = dict.fromkeys(keys)
print(result)
# Output: {'status': None, 'count': None, 'active': None}
Warning: mutable default values are shared across all keys:
# WRONG: All keys reference same list
result = dict.fromkeys(['a', 'b', 'c'], [])
result['a'].append(1)
print(result)
# Output: {'a': [1], 'b': [1], 'c': [1]} # All modified!
# CORRECT: Use comprehension for mutable defaults
result = {key: [] for key in ['a', 'b', 'c']}
result['a'].append(1)
print(result)
# Output: {'a': [1], 'b': [], 'c': []}
Performance Considerations
Different conversion methods have varying performance characteristics for large datasets.
import timeit
# Setup
setup = """
keys = [f'key_{i}' for i in range(10000)]
values = list(range(10000))
pairs = list(zip(keys, values))
"""
# Method 1: dict() with zip
time1 = timeit.timeit('dict(zip(keys, values))', setup=setup, number=1000)
# Method 2: Dictionary comprehension
time2 = timeit.timeit('{k: v for k, v in zip(keys, values)}', setup=setup, number=1000)
# Method 3: dict() with pairs
time3 = timeit.timeit('dict(pairs)', setup=setup, number=1000)
print(f"dict(zip()): {time1:.4f}s")
print(f"Dict comp: {time2:.4f}s")
print(f"dict(pairs): {time3:.4f}s")
For most use cases, dict(zip()) offers the best balance of readability and performance. Use dictionary comprehensions when you need transformations or filtering. Pre-zipped pairs with dict() are fastest when pairs already exist.
Error Handling
Robust conversion code validates input and handles edge cases:
def safe_list_to_dict(data, key_index=0, value_index=1):
"""Convert list to dictionary with validation."""
if not data:
return {}
if not isinstance(data, list):
raise TypeError(f"Expected list, got {type(data).__name__}")
result = {}
for i, item in enumerate(data):
try:
if isinstance(item, (list, tuple)):
key = item[key_index]
value = item[value_index]
else:
raise ValueError(f"Item at index {i} is not a sequence")
if not isinstance(key, (str, int, float, tuple)):
raise TypeError(f"Unhashable key type: {type(key).__name__}")
result[key] = value
except IndexError:
raise IndexError(f"Item at index {i} has insufficient elements")
return result
# Usage
data = [['a', 1], ['b', 2], ['c', 3]]
print(safe_list_to_dict(data))
# Output: {'a': 1, 'b': 2, 'c': 3}
This comprehensive approach to list-to-dictionary conversion covers the practical scenarios you’ll encounter in production code. Choose the method that matches your data structure and transformation requirements.