2

I would like to convert a Python dictionary of the following form:

D = {'a':[1,2,3], 'b':[0.1,0.5], 'c':[10,20]}

into a list of dictionaries the following form:

E = [{a:1,b:0.1,c:10}, {a:1,b:0.1,c:20},{a:1,b:0.5,c:10}, ...., {a:3,b:0.5,c:20}]

I have tried using itertools but I do not understand how to use it to make combinations of dictionaries.

user58925
  • 1,537
  • 5
  • 19
  • 28
  • 2
    What have you accomplished with `itertools`? Have you managed to make a cartesian product of your lists? – Aran-Fey Mar 07 '19 at 09:27

5 Answers5

3

Here is a solution:

import itertools

D = {'a':[1,2,3], 'b':[0.1,0.5], 'c':[10,20]}

E = [dict(zip(D.keys(), a)) for a in itertools.product(*D.values())]

This yields:

E= [{'a': 1, 'b': 0.1, 'c': 10},
 {'a': 1, 'b': 0.1, 'c': 20},
 {'a': 1, 'b': 0.5, 'c': 10},
 {'a': 1, 'b': 0.5, 'c': 20},
 {'a': 2, 'b': 0.1, 'c': 10},
 {'a': 2, 'b': 0.1, 'c': 20},
 {'a': 2, 'b': 0.5, 'c': 10},
 {'a': 2, 'b': 0.5, 'c': 20},
 {'a': 3, 'b': 0.1, 'c': 10},
 {'a': 3, 'b': 0.1, 'c': 20},
 {'a': 3, 'b': 0.5, 'c': 10},
 {'a': 3, 'b': 0.5, 'c': 20}]

Edit: Removed ordered dict as Aran points out, here is documentation to support it:Python dictionary: are keys() and values() always the same order?

Christian Sloper
  • 7,440
  • 3
  • 15
  • 28
  • `OrderedDict` is not necessary here. While yes, dict iteration order is arbitrary, it won't magically change for no reason. It can only change if you *modify* the dictionary, which you're not doing. – Aran-Fey Mar 07 '19 at 09:44
2

Why not just:

from itertools import product
D = {'a':[1,2,3], 'b':[0.1,0.5], 'c':[10,20]}
print([dict(zip(D.keys(),v)) for v in product(*D.values())])

Output:

[{'a': 1, 'b': 0.1, 'c': 10}, {'a': 1, 'b': 0.1, 'c': 20}, {'a': 1, 'b': 0.5, 'c': 10}, {'a': 1, 'b': 0.5, 'c': 20}, {'a': 2, 'b': 0.1, 'c': 10}, {'a': 2, 'b': 0.1, 'c': 20}, {'a': 2, 'b': 0.5, 'c': 10}, {'a': 2, 'b': 0.5, 'c': 20}, {'a': 3, 'b': 0.1, 'c': 10}, {'a': 3, 'b': 0.1, 'c': 20}, {'a': 3, 'b': 0.5, 'c': 10}, {'a': 3, 'b': 0.5, 'c': 20}]
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
1

One option is to simply use nested for loops; if the original data is not too big, then this will work fine and you won't need itertools to get it working.

>>> origin = {
    'a': [1, 2, 3],
    'b': [0.1, 0.5],
    'c': [10, 20],
}
>>> result = [
    {
        'a': a,
        'b': b,
        'c': c,
    }
    for a in origin['a']
    for b in origin['b']
    for c in origin['c']]
>>> result
[{'a': 1, 'b': 0.1, 'c': 10}, {'a': 1, 'b': 0.1, 'c': 20},
 {'a': 1, 'b': 0.5, 'c': 10}, {'a': 1, 'b': 0.5, 'c': 20},
 {'a': 2, 'b': 0.1, 'c': 10}, {'a': 2, 'b': 0.1, 'c': 20},
 {'a': 2, 'b': 0.5, 'c': 10}, {'a': 2, 'b': 0.5, 'c': 20},
 {'a': 3, 'b': 0.1, 'c': 10}, {'a': 3, 'b': 0.1, 'c': 20},
 {'a': 3, 'b': 0.5, 'c': 10}, {'a': 3, 'b': 0.5, 'c': 20}]
Ralf
  • 16,086
  • 4
  • 44
  • 68
  • 1
    What happens if there are a lot of keys or OP doesn't know any of the keys? – U13-Forward Mar 07 '19 at 09:49
  • @U9-Forward My answer is NOT very practical for bigger amounts of keys and not really scalable; but since the question did not specify scalabiliy as a requirement, I wanted to add an alternative solution to all the `itertools` answers. – Ralf Mar 07 '19 at 09:51
1

I developed a round about answer

parameter_values_each = {'a':[1,2,3], 'b':[0.1,0.5], 'c':[10,20]}

param_possibilities = []
for name in parameter_values_each:
    temp = []
    for val in parameter_values_each[name]:
        temp.append((name,val))
    param_possibilities.append(temp)


result = list(itertools.product(*param_possibilities))

print result
user58925
  • 1,537
  • 5
  • 19
  • 28
0

Long way with no itertools (or this is what going on inside product):

D = {'a': [1, 2, 3], 'b': [0.1, 0.5], 'c': [10, 20]}
E = []

list_of_keys = list(D.keys())
list_of_lengths = [len(D[key]) for key in list_of_keys]

product_number = 1
for length in list_of_lengths:
    product_number *= length

for n in range(product_number):
    index = n
    index_list = []
    for length in reversed(list_of_lengths):
        index_list.insert(0, index % length)
        index = index // length
    keys_with_values = {}
    for j, key in enumerate(list_of_keys):
        keys_with_values[key] = D[key][index_list[j]]
    E.append(keys_with_values)

for e in E:
    print(e)

Result:

{'a': 1, 'b': 0.1, 'c': 10}
{'a': 1, 'b': 0.1, 'c': 20}
{'a': 1, 'b': 0.5, 'c': 10}
{'a': 1, 'b': 0.5, 'c': 20}
{'a': 2, 'b': 0.1, 'c': 10}
{'a': 2, 'b': 0.1, 'c': 20}
{'a': 2, 'b': 0.5, 'c': 10}
{'a': 2, 'b': 0.5, 'c': 20}
{'a': 3, 'b': 0.1, 'c': 10}
{'a': 3, 'b': 0.1, 'c': 20}
{'a': 3, 'b': 0.5, 'c': 10}
{'a': 3, 'b': 0.5, 'c': 20}
Alex Lopatin
  • 682
  • 4
  • 8