How to Convert a List of Lists to a Dictionary in Python
Transforming nested lists into dictionaries is a common data cleaning task when processing CSV files, database results, or API responses. The right approach depends on the structure of your data: whether you have key-value pairs, parallel lists, tabular data with headers, or grouped categories.
In this guide, you will learn multiple methods to convert lists of lists into dictionaries, handle edge cases like duplicate keys and unequal lengths, and choose the best approach for your specific data structure.
Converting a List of Pairs to a Dictionary
When each inner list contains exactly two elements representing a key and a value, pass the list directly to the dict() constructor:
data = [
["name", "Alice"],
["age", 30],
["city", "New York"]
]
user = dict(data)
print(user)
Output:
{'name': 'Alice', 'age': 30, 'city': 'New York'}
This also works with tuples:
data = [("a", 1), ("b", 2), ("c", 3)]
result = dict(data)
print(result)
Output:
{'a': 1, 'b': 2, 'c': 3}
The dict() constructor accepts any iterable of two-element sequences, making it the simplest and fastest approach for this common pattern.
Merging Parallel Lists with zip()
When keys and values are stored in separate lists, use zip() to pair corresponding elements before converting:
keys = ["id", "name", "role"]
values = [101, "Bob", "Admin"]
user = dict(zip(keys, values))
print(user)
Output:
{'id': 101, 'name': 'Bob', 'role': 'Admin'}
Handling Unequal Lengths
By default, zip() stops at the shortest list without any warning, which can cause silent data loss:
keys = ["a", "b", "c", "d"]
values = [1, 2]
result = dict(zip(keys, values))
print(result)
Output:
{'a': 1, 'b': 2}
The keys "c" and "d" are silently dropped. To include all keys and fill missing values with a default, use itertools.zip_longest():
from itertools import zip_longest
keys = ["a", "b", "c", "d"]
values = [1, 2]
result = dict(zip_longest(keys, values, fillvalue=None))
print(result)
Output:
{'a': 1, 'b': 2, 'c': None, 'd': None}
In Python 3.10+, you can use zip(keys, values, strict=True) to raise a ValueError if the lists have different lengths, catching the mismatch early instead of losing data silently.
Converting Tabular Data to an Indexed Dictionary
When you have rows of data and want to index them by a specific column, use a dictionary comprehension:
rows = [
[1, "Alice", "Engineer"],
[2, "Bob", "Designer"],
[3, "Charlie", "Manager"]
]
# Index by the first column (ID)
staff_db = {row[0]: row[1:] for row in rows}
print(staff_db)
print(staff_db[2])
Output:
{1: ['Alice', 'Engineer'], 2: ['Bob', 'Designer'], 3: ['Charlie', 'Manager']}
['Bob', 'Designer']
Adding Named Fields with Headers
For more readable output, combine headers with each row using zip():
headers = ["id", "name", "role"]
rows = [
[1, "Alice", "Engineer"],
[2, "Bob", "Designer"]
]
# Create a list of dictionaries with named fields
records = [dict(zip(headers, row)) for row in rows]
print(records)
# Or index by ID with full named records
staff_db = {row[0]: dict(zip(headers[1:], row[1:])) for row in rows}
print(staff_db)
Output:
[{'id': 1, 'name': 'Alice', 'role': 'Engineer'}, {'id': 2, 'name': 'Bob', 'role': 'Designer'}]
{1: {'name': 'Alice', 'role': 'Engineer'}, 2: {'name': 'Bob', 'role': 'Designer'}}
Using the First Element as Key, Rest as Values
When each inner list uses its first element as a category name and the remaining elements as the associated values:
data = [
["fruits", "apple", "banana", "orange"],
["colors", "red", "blue", "green"],
["sizes", "small", "medium", "large"]
]
result = {row[0]: row[1:] for row in data}
print(result)
Output:
{'fruits': ['apple', 'banana', 'orange'], 'colors': ['red', 'blue', 'green'], 'sizes': ['small', 'medium', 'large']}
Handling Duplicate Keys
When keys repeat in your data, the default behavior of dict() keeps only the last value for each key:
data = [
["a", 1],
["b", 2],
["a", 3]
]
result = dict(data)
print(result)
Output:
{'a': 3, 'b': 2}
Collecting All Values for Duplicate Keys
To preserve all values associated with a repeated key, use defaultdict(list):
from collections import defaultdict
data = [
["fruit", "apple"],
["color", "red"],
["fruit", "banana"],
["fruit", "orange"]
]
result = defaultdict(list)
for key, value in data:
result[key].append(value)
print(dict(result))
Output:
{'fruit': ['apple', 'banana', 'orange'], 'color': ['red']}
This pattern is common when grouping related records by a shared key.
Converting Nested Lists to Nested Dictionaries
When your data has a recursive structure where values are themselves lists of key-value pairs, a recursive function handles the conversion at every level:
def nested_to_dict(nested_list):
"""Recursively convert nested lists of pairs to dictionaries."""
if isinstance(nested_list, list):
if all(isinstance(item, list) and len(item) == 2 for item in nested_list):
return {k: nested_to_dict(v) for k, v in nested_list}
return nested_list
data = [
["user", [["name", "Alice"], ["age", 30]]],
["settings", [["theme", "dark"], ["lang", "en"]]]
]
result = nested_to_dict(data)
print(result)
Output:
{'user': {'name': 'Alice', 'age': 30}, 'settings': {'theme': 'dark', 'lang': 'en'}}
Converting a Matrix to a Coordinate Dictionary
For 2D grids or matrices, you can create a dictionary using (row, col) tuples as keys for efficient coordinate-based lookups:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
grid = {
(row, col): value
for row, values in enumerate(matrix)
for col, value in enumerate(values)
}
print(grid[(0, 0)])
print(grid[(1, 1)])
print(grid[(2, 2)])
Output:
1
5
9
Practical Example: CSV-Style Data Processing
A common real-world scenario is processing raw CSV data where the first row contains headers and subsequent rows contain records:
csv_data = [
["id", "name", "email", "department"],
["1", "Alice", "alice@example.com", "Engineering"],
["2", "Bob", "bob@example.com", "Design"],
["3", "Charlie", "charlie@example.com", "Marketing"]
]
headers = csv_data[0]
rows = csv_data[1:]
# Convert to a list of dictionaries
records = [dict(zip(headers, row)) for row in rows]
# Build a lookup dictionary indexed by ID
by_id = {record['id']: record for record in records}
print(by_id['2'])
Output:
{'id': '2', 'name': 'Bob', 'email': 'bob@example.com', 'department': 'Design'}
This two-step approach, first creating named records, then building an index, is a pattern you will use frequently when processing tabular data.
Performance Comparison
import timeit
pairs = [[f"key_{i}", i] for i in range(100_000)]
def with_dict():
return dict(pairs)
def with_comprehension():
return {k: v for k, v in pairs}
print(f"dict(): {timeit.timeit(with_dict, number=100):.4f}s")
print(f"Comprehension: {timeit.timeit(with_comprehension, number=100):.4f}s")
Typical output:
dict(): 0.3456s
Comprehension: 0.4567s
The dict() constructor is consistently faster for simple pair conversion because the operation is handled entirely at the C level. Dictionary comprehensions are slightly slower but offer more flexibility for transformations and filtering.
Quick Reference
| Input Structure | Method | Use Case |
|---|---|---|
[[k, v], [k, v]] | dict(data) | Simple key-value pairs |
[keys], [values] | dict(zip(keys, values)) | Parallel lists from CSV or databases |
[[id, a, b], ...] | {r[0]: r[1:] for r in rows} | Rows indexed by a column |
| Headers + rows | [dict(zip(headers, row)) for row in rows] | Named records from tabular data |
| Repeated keys | defaultdict(list) with loop | Grouping values by key |
Conclusion
Converting lists of lists to dictionaries in Python is straightforward once you match the method to your data structure. Use dict() for simple pair conversion as it is the fastest and most readable option. Use dict(zip(keys, values)) when merging parallel columns from CSV or database results. For tabular data with headers, combine zip() with a list comprehension to create named records. And when duplicate keys are expected, use defaultdict(list) to collect all values rather than losing earlier entries.
Use dict() for simple pair conversion since it is the fastest and most readable approach. Use dict(zip(keys, values)) when merging parallel lists. For complex transformations that involve filtering, type conversion, or conditional logic, dictionary comprehensions offer the most flexibility.