Digamos que tengo una lista de Python que representa rangos para algunas variables:
conditions = [['i', (1, 5)], ['j', (1, 2)]]
Esto representa que la variable i
varía de 1 a 5, y dentro de esa variable de bucle j
varía de 1 a 2. Quiero un diccionario para cada combinación posible:
{'i': 1, 'j': 1}
{'i': 1, 'j': 2}
{'i': 2, 'j': 1}
{'i': 2, 'j': 2}
{'i': 3, 'j': 1}
{'i': 3, 'j': 2}
{'i': 4, 'j': 1}
{'i': 4, 'j': 2}
{'i': 5, 'j': 1}
{'i': 5, 'j': 2}
La razón es que quiero iterar sobre ellos. Pero debido a que todo el espacio es demasiado grande, no quiero generarlos todos, almacenarlos y luego iterar sobre esa lista de diccionarios. Pensé en usar el siguiente procedimiento recursivo, pero necesito ayuda con la yield
parte. Donde debe ser ¿Cómo evito los generadores anidados?
def iteration(conditions, currentCondition, valuedIndices):
if currentCondition == len(conditions):
yield valuedIndices
else:
cond = conditions[currentCondition]
index = cond[0]
lim1 = cond[1][0]
lim2 = cond[1][1]
for ix in range(lim1, lim2 + 1):
valuedIndices[index] = ix
yield iteration(conditions, currentCondition + 1, valuedIndices)
Ahora me gustaría poder hacer:
for valued_indices in iteration(conditions, 0, {}):
...
yield
conyield from
en la última línea de su función.Respuestas:
Este es un caso en el que podría ser más fácil dar un paso atrás y comenzar de nuevo.
Comencemos separando las claves y los intervalos, usando un truco bien conocido que involucra
zip
:(La correspondencia entre los dos conserva el emparejamiento original;
intervals[i]
es el intervalo para la variablekeys[i]
para todosi
).Ahora, creemos objetos de rango adecuados a partir de esos intervalos
Podemos calcular el producto de estos
range
objetos.que debe reconocer como los valores a utilizar para cada dict. Puede comprimir cada uno de esos valores con las claves para crear un conjunto apropiado de argumentos para el
dict
comando. Por ejemplo:Al unir todo esto, podemos iterar sobre el producto para producir cada uno
dict
a su vez, produciéndolo.fuente
Quizás pueda simplificar un poco con una comprensión interna del generador y
yield from
:usar como:
fuente
dict_factory(*args)
entonces ... Hmmm ...No estoy seguro de si necesita usar la recursión específicamente o no, pero podría generarlos utilizando el método del producto itertools para generar todas las combinaciones. esto está escrito de tal manera que puede tener condiciones de 1 a n y aún debería funcionar y devolverle artículo por artículo.
SALIDA
fuente