How to Convert a List to a Dictionary in Python
Choose the right Python pattern for converting parallel lists, key-value pairs, or a single list to a dictionary—and handle duplicates safely.

Choose the conversion pattern based on how your data is shaped: use dict(zip(keys, values)) for corresponding parallel lists, dict(pairs) for existing key-value pairs, a dictionary comprehension for calculated keys or values, and dict(enumerate(items)) when list positions should become keys. Before converting, decide what should happen if two items produce the same key: a normal dictionary keeps only the later value.
These examples use built-in Python features. They do not require an import. The examples follow the Python 3.12 documentation for data structures, dictionaries, zip, enumerate, and dictionary comprehensions.
1. Choose a pattern based on the list shape
| Your input | Use | Typical result |
|---|---|---|
| Two lists with corresponding keys and values | dict(zip(keys, values)) |
A name-to-score mapping |
| A list of two-item pairs | dict(pairs) |
A mapping from each pair’s first item to its second |
| One list whose values need transforming | A dictionary comprehension | A mapping from a computed key to a computed value |
| A list whose positions are meaningful | dict(enumerate(items)) |
A zero-based index-to-item mapping |
| Repeated keys must retain every value | Group values into lists | A key-to-list mapping |
Use the form that communicates the relationship in the data. Two lists should only be zipped when items at the same position belong together. If the data already contains pairs, passing those pairs directly to dict() is simpler. If values need transformation, a comprehension makes that rule visible.
2. Convert parallel lists with zip()
When one list contains keys and the other contains their corresponding values in the same order, pair them with zip() and pass the pairs to dict():

names = ["Ada", "Linus", "Grace"]
scores = [95, 88, 97]
by_name = dict(zip(names, scores))
print(by_name)
# {'Ada': 95, 'Linus': 88, 'Grace': 97}
zip() pairs by position: the first name with the first score, the second name with the second score, and so on. This means the input lists need to represent matching sequences, not merely lists that happen to have the same length.
What if the lists have different lengths?
By default, zip() stops when its shortest input is exhausted. Extra items in a longer list are not included:
keys = ["a", "b", "c"]
values = [10, 20]
print(dict(zip(keys, values)))
# {'a': 10, 'b': 20}
This behavior can silently discard data. If you expect the lists to have equal lengths, check explicitly before converting:
if len(keys) != len(values):
raise ValueError("keys and values must have the same length")
result = dict(zip(keys, values))
When processing data that should be aligned exactly, Python also provides strict zip behavior. With zip(keys, values, strict=True), unequal lengths raise a ValueError rather than silently truncating. This option is available in Python 3.10 and later.
keys = ["a", "b", "c"]
values = [10, 20]
result = dict(zip(keys, values, strict=True))
# ValueError because the input lengths differ
3. Convert a list of key-value pairs
If each list item is already a pair, pass the list to dict(). Each pair supplies one key and one value:
pairs = [("Ada", 95), ("Linus", 88)]
by_name = dict(pairs)
print(by_name)
# {'Ada': 95, 'Linus': 88}
The pair elements can be values of different types. For example, a string may be the key and a list may be its value. The key still has to be hashable, and repeated keys still overwrite earlier values.
records = [
("users", 12),
("active", True),
("tags", ["python", "data"]),
]
settings = dict(records)
print(settings["tags"])
# ['python', 'data']
Each item must provide exactly two elements. An item with one element or three elements cannot be interpreted as a key-value pair and causes a ValueError.
bad_pairs = [("Ada", 95, "passed")]
# Raises ValueError: dictionary update sequence element has length 3
result = dict(bad_pairs)
If records are not two-item sequences—for example, dictionaries with named fields—extract the fields with a comprehension:
people = [
{"id": "u1", "name": "Ada"},
{"id": "u2", "name": "Linus"},
]
by_id = {person["id"]: person["name"] for person in people}
print(by_id)
# {'u1': 'Ada', 'u2': 'Linus'}
4. Build a dictionary with a comprehension
A dictionary comprehension is useful when a list provides the input items but you need to calculate keys, values, or both. Its general form is {key_expression: value_expression for item in iterable}.
numbers = [2, 4, 6]
squares = {number: number * number for number in numbers}
print(squares)
# {2: 4, 4: 16, 6: 36}
You can transform strings, select a field, or filter items while building the dictionary:
words = ["Ada", "Linus", "Grace"]
length_by_word = {word: len(word) for word in words}
scores = [("Ada", 95), ("Linus", 88), ("Grace", 97)]
passing = {name: score for name, score in scores if score >= 90}
print(length_by_word)
# {'Ada': 3, 'Linus': 5, 'Grace': 5}
print(passing)
# {'Ada': 95, 'Grace': 97}
Use a condition in the comprehension only when excluding items is part of the desired conversion. If every source entry must be retained, omit the filter and validate the data separately.
5. Use list positions as dictionary keys
enumerate() produces each item with its position. Passing that sequence of pairs to dict() creates a position-to-value mapping:
names = ["Ada", "Linus", "Grace"]
by_position = dict(enumerate(names))
print(by_position)
# {0: 'Ada', 1: 'Linus', 2: 'Grace'}
By default, positions start at zero. Supply a starting number when your indexing scheme begins elsewhere:
months = ["January", "February", "March"]
month_numbers = dict(enumerate(months, start=1))
print(month_numbers)
# {1: 'January', 2: 'February', 3: 'March'}
This pattern is useful when the position itself is meaningful, such as a ranking or numbered sequence. If you only need to loop through list values, you do not need to convert the list into a dictionary.
6. Decide how to handle duplicate keys
A dictionary has one value per key. If the input creates the same key more than once, the later value replaces the earlier one. The conversion succeeds, so this can be easy to miss:

pairs = [("Ada", 95), ("Linus", 88), ("Ada", 99)]
by_name = dict(pairs)
print(by_name)
# {'Ada': 99, 'Linus': 88}
If you intend to keep only the latest value, that result may be correct. If duplicates indicate invalid input, detect them before conversion:
pairs = [("Ada", 95), ("Linus", 88), ("Ada", 99)]
seen = set()
for key, value in pairs:
if key in seen:
raise ValueError(f"duplicate key: {key!r}")
seen.add(key)
by_name = dict(pairs)
If every value matters, group values under each key instead of converting to an ordinary one-value-per-key mapping:
pairs = [("Ada", 95), ("Linus", 88), ("Ada", 99)]
by_name = {}
for name, score in pairs:
by_name.setdefault(name, []).append(score)
print(by_name)
# {'Ada': [95, 99], 'Linus': [88]}
The correct policy depends on the meaning of the input: overwrite, reject duplicates, or retain all values. Choose that policy before using a conversion pattern that can hide repeated keys.
7. Check that your keys can be dictionary keys
Dictionary keys must be hashable. Strings, numbers, and tuples whose contents are themselves hashable can be keys. A list cannot be a key because it is mutable.
valid = {"region": "west", 2026: "year", ("x", "y"): "point"}
# Raises TypeError: unhashable type: 'list'
invalid = {["x", "y"]: "point"}
If a list represents a compound key, convert it to a tuple when its elements are hashable:
coordinates = [[10, 20], [30, 40]]
labels = ["first", "second"]
by_coordinate = {tuple(point): label for point, label in zip(coordinates, labels)}
print(by_coordinate)
# {(10, 20): 'first', (30, 40): 'second'}
Do not convert a list to a tuple mechanically if its elements include mutable or otherwise unhashable values. The tuple must be hashable too.
8. Complete runnable example
This script shows the common input shapes and handles duplicates by grouping when every score should be preserved:
def main():
# Parallel sequences
names = ["Ada", "Linus"]
scores = [95, 88]
if len(names) != len(scores):
raise ValueError("names and scores must have the same length")
by_name = dict(zip(names, scores, strict=True))
# Existing pairs
pairs = [("Ada", 95), ("Linus", 88)]
from_pairs = dict(pairs)
# Computed mapping
numbers = [2, 4, 6]
squares = {number: number * number for number in numbers}
# Position as key
by_position = dict(enumerate(names, start=1))
# Preserve repeated values by grouping
attempts = [("Ada", 95), ("Ada", 99), ("Linus", 88)]
scores_by_name = {}
for name, score in attempts:
scores_by_name.setdefault(name, []).append(score)
print("parallel:", by_name)
print("pairs:", from_pairs)
print("squares:", squares)
print("positions:", by_position)
print("grouped:", scores_by_name)
if __name__ == "__main__":
main()
Save it as convert.py and run python convert.py. The strict zip call requires Python 3.10 or later. On an earlier version, keep the explicit length check and use zip(names, scores) without the strict argument.
9. Troubleshooting common conversion errors
| Symptom | Likely cause | Fix |
|---|---|---|
| Some keys have no values | The parallel lists differ in length, and zip() stopped at the shorter one. |
Check lengths or use zip(..., strict=True) on Python 3.10+. |
| A value seems to have disappeared | A later item used the same key and replaced its earlier value. | Validate key uniqueness or group values into lists. |
TypeError: unhashable type |
A key is a mutable object such as a list. | Choose an immutable key, such as a tuple of hashable elements. |
ValueError about sequence element length |
An item passed to dict() does not contain exactly two elements. |
Inspect the records and extract the intended key and value explicitly. |
| Values are associated with the wrong keys | The parallel lists are not aligned in the same order. | Pair records at their source or sort/reorder both sequences using the same rule. |
| The dictionary is empty | The input iterable is empty, or a filter excluded every item. | Inspect the source and comprehension condition; an empty input produces an empty dictionary. |
10. Performance, reliability, and cost
All the patterns above use Python’s built-in dictionary construction. Choose primarily for correctness and clarity: the input shape and duplicate policy matter more than a speculative speed difference. Converting a list produces a separate dictionary that holds references to its values; it does not turn the original list into a dictionary in place.
For large inputs, remember that the dictionary must hold an entry for each distinct key, and duplicate keys still require processing even when earlier values are replaced. If you group repeated values, the grouped lists also retain each value. Avoid building a dictionary if the next operation can work directly on the original iterable.
For reliable data conversion, validate assumptions at the boundary: list lengths for parallel sequences, pair shape for records, hashability for keys, and uniqueness when overwriting is not acceptable. These checks make bad input fail clearly instead of producing a plausible but incomplete mapping.
Or skip the browser setup
If your project needs a website screenshot as an input to a Python workflow, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns an image or PDF; the API options include PNG, JPEG or WebP, full-page and element capture, viewport and device settings, and custom CSS and JavaScript. See the ScreenshotNeo API documentation for request options.
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
ScreenshotNeo accepts cookie and consent banners before capture and removes 60+ known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, with response headers indicating the page verdict and billing status. Its MCP server gives Claude, Cursor, and other MCP clients the tools take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 shots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. Learn more at ScreenshotNeo.
Sign up for 1,000 free screenshots a month, with no card required.
Frequently asked questions
Can I convert a list of values into a dictionary without separate keys?
Yes. Use dict(enumerate(items)) if each item’s position is its key. If you need a different key, calculate it with a dictionary comprehension.
Does converting a list to a dictionary preserve its order?
The conversion patterns determine key-value associations; they should not be used to infer a different ordering from the source. If order matters to your application, be explicit about the sequence you iterate and the keys you construct.
Can a dictionary contain the same key twice?
No. A dictionary has one entry per key. A later assignment updates the value for an existing key; use a list as the value if you need to retain multiple associated items.
Which method should I use for a list of dictionaries?
Use a comprehension that selects a key field and a value field, such as {row["id"]: row for row in rows}. Decide how duplicate IDs should be handled before building the result.


