Combinations from dictionary with list values using Python
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When you have a dictionary where each key maps to a list of possible values, a common task is generating every combination of those values -- one value chosen from each key. This is called the Cartesian product, and it appears in scenarios like hyperparameter tuning, configuration testing, and A/B experiment design. Python's itertools.product makes this straightforward.
Understanding the Problem
Consider a dictionary that represents configurable options:
You want every possible combination: red-S-cotton, red-S-polyester, red-M-cotton, and so on. With 2 colors, 3 sizes, and 2 materials, that gives you 2 x 3 x 2 = 12 combinations. Each combination picks exactly one value from each key.
Using itertools.product
The itertools.product function computes the Cartesian product of input iterables. To turn dictionary values into combinations and then map them back to their keys, combine it with zip:
Output:
The *values unpacking passes each list as a separate argument to itertools.product. The zip(keys, combo) call pairs each key with the corresponding value from the current combination tuple, and dict() turns those pairs into a dictionary.
A Pure List Comprehension Approach
If you prefer to avoid importing itertools, you can build the Cartesian product with nested comprehensions, though it only works cleanly when you know the number of keys in advance:
This approach is readable for two or three keys but becomes unwieldy for larger dictionaries. The itertools.product method scales to any number of keys without changing the code structure.
Real-World Example: Hyperparameter Grid Search
One of the most common uses for this pattern is generating a parameter grid for machine learning experiments:
This generates 3 x 3 x 2 = 18 configurations. Each one can be passed directly as keyword arguments to a training function.
Real-World Example: A/B Test Variant Matrix
Another practical application is generating all variants for a multivariate A/B test:
This produces 8 variants, each representing a unique combination of visual elements to test.
Filtering Combinations
In many cases you do not want every combination. You can filter results with a condition:
Filtering inside the list comprehension keeps the code concise and avoids building an intermediate list of all combinations.
Memory Considerations for Large Spaces
The Cartesian product grows multiplicatively. A dictionary with 10 keys each having 10 values produces 10 billion combinations. Building a list of all of them will exhaust your memory. Use the iterator form of itertools.product instead of materializing everything at once:
By iterating directly over itertools.product instead of wrapping it in a list comprehension, you process one combination at a time and keep memory usage constant.
Common Pitfalls
- Materializing huge products into a list causes memory errors. Use the iterator directly when the combination space is large.
- Relying on dictionary insertion order is safe in Python 3.7+ but will produce unpredictable key-value pairings in older versions. Use
collections.OrderedDictif you must support Python 3.6 or earlier. - Confusing
itertools.productwithitertools.combinations--productgives the Cartesian product (one pick from each iterable), whilecombinationsgives subsets of a single iterable. - Forgetting the
*unpacking initertools.product(*values)passes the entire list of lists as one argument instead of separate arguments, producing wrong results. - Hardcoding key names in list comprehensions breaks when keys change. The
dict(zip(keys, combo))pattern is dynamic and adapts to any dictionary.
Summary
- Use
itertools.product(*dict.values())to compute the Cartesian product of all value lists. - Reconstruct dictionaries with
dict(zip(dict.keys(), combo))to map each combination back to its keys. - Filter combinations inside the comprehension to avoid building a full intermediate list.
- For large combination spaces, iterate over the product directly instead of materializing it into a list.
- This pattern is widely used in hyperparameter grid search, A/B test variant generation, and configuration testing.

