Tengo un diccionario con valores en ints, bools, y cadenas y listas y una lista ordenada de claves en la que quiero la lista final de listas. Quiero la salida de modo que donde haya una lista, hagamos combinaciones de eso con valores únicos.

Entrada:

cols = ['region', 'city', 'country', 'valid'] 
vals = {'city': [10, 20], 'valid': True, 'region': 3, 'country': 'US'}

Salida:

[[3, 10, 'US', True], [3, 20, 'US', True]]

Ahora, si otro campo es una lista, aumentaría las combinaciones.

Entrada:

cols = ['region', 'city', 'country', 'valid'] 
vals = {'city': [10, 20], 'valid': True, 'region': [3, 4], 'country': 'US'}

Salida:

[[3, 10, 'US', True], [3, 20, 'US', True], [4, 10, 'US', True], [4, 20, 'US', True]]

Buscando la forma más pitónica de lograr esto.

0
umarr 9 oct. 2019 a las 11:47

3 respuestas

La mejor respuesta

Utilice itertools.product:

import itertools

cols = ['region', 'city', 'country', 'valid'] 
vals = {'city': [10, 20], 'valid': True, 'region': [3, 4], 'country': 'US'}

values = [vals[key] for key in cols]
values = [val if isinstance(val, list) else [val] for val in values]

result = list(itertools.product(*values))
print(result)
# [(3, 10, 'US', True), (3, 20, 'US', True), (4, 10, 'US', True), (4, 20, 'US', True)]

Lectura relacionada:

3
Aran-Fey 9 oct. 2019 a las 10:01

Puede usar itertools.product para los campos respectivos como,

Pero antes de hacer product, debe verificar si es una instancia de int o str, en caso afirmativo, luego conviértalos en list o {{X4} } por el bien de la iteración correcta

>>> vals = {'city': [10, 20], 'valid': True, 'region': 3, 'country': 'US'}
>>> 
>>> city = vals['city']
>>> region = vals['region']
>>> country = vals['country']
>>> 
>>> if not isinstance(region, (list, tuple)):
...   region = [region]
... 
>>> if not isinstance(country, (list, tuple)):
...   country = [country]
... 
>>> list(product(region, city, country, [vals['valid']]))
[(3, 10, 'US', True), (3, 20, 'US', True)]


>>> vals
{'city': [10, 20], 'valid': True, 'region': [3, 4], 'country': 'US'}
>>> from itertools import product
>>> list(product(vals['region'], vals['city'], [vals['country']], [vals['valid']]))
[(3, 10, 'US', True), (3, 20, 'US', True), (4, 10, 'US', True), (4, 20, 'US', True)]

Podrías escribir una función para manejar eso como,

$ cat mkcomb.py
from itertools import product


def mk_comb(keys, vals):
    values = [
      vals[key] if isinstance(vals[key], (list, tuple)) else [vals[key]]
      for key in keys
    ]
    return list(product(*values))

cols = ['region', 'city', 'country', 'valid'] 
vals1 = {'city': [10, 20], 'valid': True, 'region': 3, 'country': 'US'}
vals2 = {'city': [10, 20], 'valid': True, 'region': [3, 4], 'country': 'US'}
print(mk_comb(cols, vals1))
print(mk_comb(cols, vals2))

Salida:

$ python mkcomb.py
[(3, 10, 'US', True), (3, 20, 'US', True)]
[(3, 10, 'US', True), (3, 20, 'US', True), (4, 10, 'US', True), (4, 20, 'US', True)]
2
han solo 9 oct. 2019 a las 09:20

La comprensión de la lista puede hacer el trabajo por usted:

list(itertools.product(*[vals[c] if type(vals[c]) == list else [vals[c]] for c in cols]))
0
tituszban 9 oct. 2019 a las 08:57
58300302