MSeifert
MSeifert

Reputation: 152675

Explode a dict - Get all combinations of the values in a dictionary

I want to get all combinations of the values in a dictionary as multiple dictionaries (each containing every key of the original but only one value of the original values). Say I want to parametrize a function call with:

kwargs = {'a': [1, 2, 3], 'b': [1, 2, 3]}

How do I get a list of all the combinations like this:

combinations = [{'a': 1, 'b': 1}, {'a': 1, 'b': 2}, {'a': 1, 'b': 3},
                {'a': 2, 'b': 1}, {'a': 2, 'b': 2}, {'a': 2, 'b': 3},
                {'a': 3, 'b': 1}, {'a': 3, 'b': 2}, {'a': 3, 'b': 3}]

There can be an arbitary amount of keys in the original kwargs and each value is garantueed to be an iterable but the number of values is not fixed.

If possible: the final combinations should be a generator (not a list).

Upvotes: 6

Views: 10650

Answers (2)

Stefan Pochmann
Stefan Pochmann

Reputation: 28606

Just another way, building the value tuples first and then combining with keys afterwards (pretty much the opposite of @thefourtheye's way :-).

>>> combinations = (dict(zip(kwargs, vs)) for vs in product(*kwargs.values()))
>>> for c in combinations:
        print(c)

{'a': 1, 'b': 1}
{'a': 1, 'b': 2}
{'a': 1, 'b': 3}
{'a': 2, 'b': 1}
{'a': 2, 'b': 2}
{'a': 2, 'b': 3}
{'a': 3, 'b': 1}
{'a': 3, 'b': 2}
{'a': 3, 'b': 3}

Upvotes: 4

thefourtheye
thefourtheye

Reputation: 239513

You can flatten the kwargs to something like this

>>> kwargs = {'a': [1, 2, 3], 'b': [1, 2, 3]}
>>> flat = [[(k, v) for v in vs] for k, vs in kwargs.items()]
>>> flat
[[('b', 1), ('b', 2), ('b', 3)], [('a', 1), ('a', 2), ('a', 3)]]

Then, you can use itertools.product like this

>>> from itertools import product
>>> [dict(items) for items in product(*flat)]
[{'a': 1, 'b': 1},
 {'a': 2, 'b': 1},
 {'a': 3, 'b': 1},
 {'a': 1, 'b': 2},
 {'a': 2, 'b': 2},
 {'a': 3, 'b': 2},
 {'a': 1, 'b': 3},
 {'a': 2, 'b': 3},
 {'a': 3, 'b': 3}]

itertools.product actually returns an iterator. So you can get the values on demand and build your dictionaries. Or you can use map, which also returns an iterator.

>>> for item in map(dict, product(*flat)):
...     print(item)
...
...
{'b': 1, 'a': 1}
{'b': 1, 'a': 2}
{'b': 1, 'a': 3}
{'b': 2, 'a': 1}
{'b': 2, 'a': 2}
{'b': 2, 'a': 3}
{'b': 3, 'a': 1}
{'b': 3, 'a': 2}
{'b': 3, 'a': 3}

Upvotes: 10

Related Questions