1

I have a python dictionary which includes some nested lists and might look as follows:

Dict = {
"a": [0.1, 20],
"b": 300,
"c": ["sun", "moon"],
"d": "water",
}

I am now trying to generate all possible unique permutations of this dictionary where each key only has one entry (i.e. no nested lists anymore). The desired dictionaries would look like these:

Dict1 = {
"a": 0.1,
"b": 300,
"c": "sun",
"d": "water",
}

Dict2 = {
"a": 0.1,
"b": 300,
"c": "moon",
"d": "water",
}

Dict3 = {
"a": 20,
"b": 300,
"c": "sun",
"d": "water",
}

Dict4 = {
"a": 20,
"b": 300,
"c": "moon",
"d": "water",
}

After looking at comparable problems I have tried my luck with itertools but have not succeeded thus far. I am rather new to pyhton and am also not sure if dictionaries are even the most appropriate datastructure for this problem, so any advice will me much appreciated.

import itertools 
keys, values = zip(*Dict.items()) 
results = [dict(zip(keys, v)) for v in itertools.product(values)] 
azro
  • 53,056
  • 7
  • 34
  • 70
phazon
  • 23
  • 2

2 Answers2

3

It is better to put the resulting dicts in a list rather than assigning them to unrelated variables.

We can use itertools.product to create the values, but we have to take care before and put the 'isolated values' like your integer and your string in a list of its own. We leave the lists and tuples as they are, you can adjust the rule to your own needs.

Then, we can create the list of dicts by reassembling the keys with the values.

from itertools import product

data = {
"a": [0.1, 20],
"b": 300,
"c": ["sun", "moon"],
"d": "water",
}

product_values = product(*[v if isinstance(v, (list, tuple)) else [v] for v in data.values()])
out = [dict(zip(data.keys(), values)) for values in product_values]
print(out)
# [{'a': 0.1, 'b': 300, 'c': 'sun', 'd': 'water'}, 
#  {'a': 0.1, 'b': 300, 'c': 'moon', 'd': 'water'},
#  {'a': 20, 'b': 300, 'c': 'sun', 'd': 'water'}, 
#  {'a': 20, 'b': 300, 'c': 'moon', 'd': 'water'}]
Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
2

You can iterate over the mappings that you have, and

  • if the value is a list : you combine existing dicts with all values (a product)
  • if the value is is single, you just add it to each dict
def expand_dd(dd):
    result = [{}]
    for key, value in dd.items():
        if isinstance(value, list):
            result = [{**d, key: v} for d in result for v in value]
        else:
            result = [{**d, key: value} for d in result]
    return result



dd = {"a": [0.1, 20], "b": 300, "c": ["sun", "moon"], "d": "water"}
e = expand_dd(dd)
print(e)
# [{'a': 0.1, 'b': 300, 'c': 'sun', 'd': 'water'},
#  {'a': 0.1, 'b': 300, 'c': 'moon', 'd': 'water'},
#  {'a': 20, 'b': 300, 'c': 'sun', 'd': 'water'},
#  {'a': 20, 'b': 300, 'c': 'moon', 'd': 'water'}]
azro
  • 53,056
  • 7
  • 34
  • 70