Tengo un diccionario con variables:

variables = {
    'a': ['x','y','z'],
    'b': [1,2,3,4],
    'c': ['xx','yy','zz']
}

Y para cada combinación potencial de variables, me gustaría hacer un escenario separado, así:

scenarios = {
    1: {a: 'x', b: 1, c: 'xx'},
    2: {a: 'y', b: 1, c: 'xx'},
    3: {a: 'z', b: 1, c: 'xx'},
    4: {a: 'x', b: 2, c: 'xx'},
    5: {a: 'y', b: 2, c: 'xx'},
    6: {a: 'z', b: 2, c: 'xx'},
    7: {a: 'x', b: 3, c: 'xx'},
    8: {a: 'y', b: 3, c: 'xx'},
    9: {a: 'z', b: 3, c: 'xx'},
    .. }

¿Cómo hacer esto?

1
Maurice Kroon 24 feb. 2018 a las 01:14

3 respuestas

La mejor respuesta

Puede usar una combinación de diccionario anidado con zip, enumerate, y itertools.product.

>>> {i: {n: v for n, v in zip(names, p)} 
...  for names, values in [zip(*variables.items())]
...  for i, p in enumerate(itertools.product(*values), start=1)}
...
{1: {'a': 'x', 'b': 1, 'c': 'xx'},
 2: {'a': 'x', 'b': 2, 'c': 'xx'},
 3: {'a': 'x', 'b': 3, 'c': 'xx'},
 ...
 36: {'a': 'z', 'b': 4, 'c': 'zz'}}

Sin embargo, esto genera los elementos en un orden diferente. Si desea su pedido exacto, puede revertir-ordenar los artículos antes de calcular el producto:

>>> {i: {n: v for n, v in zip(names, p)}
...  for names, values in [zip(*sorted(variables.items(), reverse=True))]
...  for i, p in enumerate(itertools.product(*values), start=1)}
...
{1: {'a': 'x', 'b': 1, 'c': 'xx'},
 2: {'a': 'y', 'b': 1, 'c': 'xx'},
 3: {'a': 'z', 'b': 1, 'c': 'xx'},
 ...

Ambos funcionarán con cualquier número de variables.

2
tobias_k 23 feb. 2018 a las 22:36

Puede recorrer fácilmente todas las combinaciones con bucles for anidados.

variables = {
  'a': ['x','y','z'],
  'b': [1,2,3,4],
  'c': ['xx','yy','zz']
}

# New dict
scenarios = {}
i = 0

# iterates through all values of each dict item
for a_value in variables['a']:
  for b_value in variables['b']:
    for c_value in variables['c']:
      scenarios[i] = {'a': a_value, 'b': b_value, 'c' : c_value}
      i += 1

Para comprobar que esto produce el resultado deseado, puede ejecutar lo siguiente:

for key in sinarios:
  print(key, sinarios[key])
0
Andrew 23 feb. 2018 a las 22:34

Puede usar itertools y string para una solución corta:

import itertools
from string import ascii_lowercase as l
variables = {
'a': ['x','y','z'],
'b': [1,2,3,4],
'c': ['xx','yy','zz']
}
new_vars = {i:dict(zip(l[:3], a)) for i, a in enumerate(itertools.product(*[variables[i] for i in l[:3]]), start=1)}

Salida:

{1: {'a': 'x', 'c': 'xx', 'b': 1}, 2: {'a': 'x', 'c': 'yy', 'b': 1}, 3: {'a': 'x', 'c': 'zz', 'b': 1}, 4: {'a': 'x', 'c': 'xx', 'b': 2}, 5: {'a': 'x', 'c': 'yy', 'b': 2}, 6: {'a': 'x', 'c': 'zz', 'b': 2}, 7: {'a': 'x', 'c': 'xx', 'b': 3}, 8: {'a': 'x', 'c': 'yy', 'b': 3}, 9: {'a': 'x', 'c': 'zz', 'b': 3}, 10: {'a': 'x', 'c': 'xx', 'b': 4}, 11: {'a': 'x', 'c': 'yy', 'b': 4}, 12: {'a': 'x', 'c': 'zz', 'b': 4}, 13: {'a': 'y', 'c': 'xx', 'b': 1}, 14: {'a': 'y', 'c': 'yy', 'b': 1}, 15: {'a': 'y', 'c': 'zz', 'b': 1}, 16: {'a': 'y', 'c': 'xx', 'b': 2}, 17: {'a': 'y', 'c': 'yy', 'b': 2}, 18: {'a': 'y', 'c': 'zz', 'b': 2}, 19: {'a': 'y', 'c': 'xx', 'b': 3}, 20: {'a': 'y', 'c': 'yy', 'b': 3}, 21: {'a': 'y', 'c': 'zz', 'b': 3}, 22: {'a': 'y', 'c': 'xx', 'b': 4}, 23: {'a': 'y', 'c': 'yy', 'b': 4}, 24: {'a': 'y', 'c': 'zz', 'b': 4}, 25: {'a': 'z', 'c': 'xx', 'b': 1}, 26: {'a': 'z', 'c': 'yy', 'b': 1}, 27: {'a': 'z', 'c': 'zz', 'b': 1}, 28: {'a': 'z', 'c': 'xx', 'b': 2}, 29: {'a': 'z', 'c': 'yy', 'b': 2}, 30: {'a': 'z', 'c': 'zz', 'b': 2}, 31: {'a': 'z', 'c': 'xx', 'b': 3}, 32: {'a': 'z', 'c': 'yy', 'b': 3}, 33: {'a': 'z', 'c': 'zz', 'b': 3}, 34: {'a': 'z', 'c': 'xx', 'b': 4}, 35: {'a': 'z', 'c': 'yy', 'b': 4}, 36: {'a': 'z', 'c': 'zz', 'b': 4}}
0
Ajax1234 23 feb. 2018 a las 22:39