Skip to main content

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}
tip

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 StructureMethodUse 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 keysdefaultdict(list) with loopGrouping 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.

Best Practice

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.