Reputation: 1373
Given a dictionary containing lists with different lengths but not only, e.g.
d = {foo: 'hello', bar: [0, 2], baz: [1, 2, 3]}
I would like to create a list of all possible combinations where each combination is a dictionary:
l = [{foo: 'hello', bar: 0, baz: 1},
{foo: 'hello', bar: 0, baz: 2},
{foo: 'hello', bar: 0, baz: 3},
{foo: 'hello', bar: 2, baz: 1},
{foo: 'hello', bar: 2, baz: 2},
{foo: 'hello', bar: 2, baz: 3}]
The order does not matter here and I don't need to transform back the list into a dictionary.
It is of course possible to perform this operation with Python loops but I'm looking for a solution which is more efficient and/or more elegant.
Upvotes: 1
Views: 57
Reputation: 1373
The algorithm below answers the question in a generic way:
def list_of_dictionaries(self, dictionary):
# values which are not lists are forced to be lists
for k, v in dictionary.items():
if type(v) is not list:
dictionary[k] = [v]
# list all combinations of values
combinations = [list(x) for x in dictionary.values() if isinstance(x, list)]
combinations = list(itertools.product(*combinations))
# create list of dictionaries
list_of_dicts = []
for values in combinations:
dict_element = {}
for i, k in enumerate(dictionary.keys()):
dict_element[k] = values[i]
list_of_dicts.append(dict_element)
return list_of_dicts
Upvotes: 0
Reputation: 13152
I feel like the answer by @DSteman is basically correct and they have given you the tools you need to solve your issue.
I see you are getting stuck on how to finish up given their excellent starting suggestion. So here is a simpler more explicit version that lacks the flexibility they have included but directly produces the result you seek.
If you feel this solves your question I strongly recommend you revisit their answer and consider it as the "solution".
import itertools
data_in = {"foo": "hello", "bar": [0, 2], "baz": [1, 2, 3]}
data_out = [
{"foo": data_in["foo"], "bar": c[0], "baz": c[1]}
for c in itertools.product(data_in["bar"], data_in["baz"])
]
print(data_out)
this will produce:
[
{'foo': 'hello', 'bar': 0, 'baz': 1},
{'foo': 'hello', 'bar': 0, 'baz': 2},
{'foo': 'hello', 'bar': 0, 'baz': 3},
{'foo': 'hello', 'bar': 2, 'baz': 1},
{'foo': 'hello', 'bar': 2, 'baz': 2},
{'foo': 'hello', 'bar': 2, 'baz': 3}
]
Upvotes: 2
Reputation: 1658
Itertools would be great for this. The code could look something like this:
import itertools
d = {'foo': 'hello', 'bar': [0, 2], 'baz': [1, 2, 3]}
a = [list(x) for x in d.values() if isinstance(x, list)]
constant_values = [x for x in d.values() if x not in a]
keys = d.keys()
combinations = list(itertools.product(*a))
Just transform it into a dictionary as the last step using constant_values and keys
Upvotes: 2