Noe*_*che 8 python recursion yield
假设我有一个表示某些变量范围的 Python 列表:
conditions = [['i', (1, 5)], ['j', (1, 2)]]
Run Code Online (Sandbox Code Playgroud)
这表示变量i范围从 1 到 5,在该循环变量j范围内从 1 到 2。我想要每个可能的组合的字典:
{'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}
Run Code Online (Sandbox Code Playgroud)
原因是我想迭代它们。但是因为整个空间太大,我不想生成所有这些,存储它们然后迭代那个字典列表。我考虑过使用以下递归过程,但我需要这部分的帮助yield。它应该在哪里?如何避免嵌套生成器?
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)
Run Code Online (Sandbox Code Playgroud)
现在我希望能够做到:
for valued_indices in iteration(conditions, 0, {}):
...
Run Code Online (Sandbox Code Playgroud)
在这种情况下,退一步重新开始可能更容易。
让我们首先使用一个众所周知的技巧将键和间隔分开zip:
>>> keys, intervals = list(zip(*conditions))
>>> keys
('i', 'j')
>>> intervals
((1, 5), (1, 2))
Run Code Online (Sandbox Code Playgroud)
(两者之间的对应关系保留了原始配对;intervals[i]是keys[i]所有变量的区间i。)
现在,让我们从这些间隔创建适当的范围对象
>>> intervals = [range(x, y+1) for x, y in intervals]
>>> list(intervals[0])
[1, 2, 3, 4, 5]
>>> list(intervals[1])
[1, 2]
Run Code Online (Sandbox Code Playgroud)
我们可以计算这些range对象的乘积
>>> for v in product(*intervals):
... print(v)
...
(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
(4, 1)
(4, 2)
(5, 1)
(5, 2)
Run Code Online (Sandbox Code Playgroud)
您应该将其识别为用于每个字典的值。您可以使用键压缩这些值中的每一个,以便为该dict命令创建一组适当的参数。例如:
>>> dict(zip(keys, (1,1)))
{'i': 1, 'j': 1}
Run Code Online (Sandbox Code Playgroud)
将所有这些放在一起,我们可以迭代产品以dict依次生产每个产品,从而产生它。
def iteration(conditions):
keys, intervals = zip(*conditions)
intervals = [range(x, y+1) for x, y in intervals]
yield from (dict(zip(keys, v)) for v in product(*intervals))
Run Code Online (Sandbox Code Playgroud)