根据 http://docs.python.org/2/library/itertools.html#itertools.product以下函数等同于使用他们的库(我从中删除了一些我不需要的东西):
def product(*args):
# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
pools = map(tuple, args)
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
在我的例子中,我传递了 product function 3 列表,但我需要添加一些条件检查,因此它不会将一个列表中的某些项目与另一个列表中的项目混合,如果它们不符合要求。所以我认为我需要做的是转换:
result = [x+[y] for x in result for y in pool]
进入“正常”FOR 循环(不确定如何引用它们),因此我可以添加几个 IF 检查来验证列表中的项目是否应该混合在一起。
主要让我感到困惑的是“x”正在遍历空的“结果”列表,但是在它迭代时会向其中添加项目,所以我认为这就是使我转换为正常循环变得复杂的原因。
这是我的一个尝试:
def product(*args):
pools = map(tuple, args)
result = [[]]
for pool in pools:
for x in result:
for y in pool:
result.append(x+[y])
for prod in result:
yield tuple(prod)
非常感谢任何帮助!
最佳答案
您非常接近:嵌套列表推导式右侧的书写顺序与您编写 for 循环的顺序相同,所以您做对了。但是,在 listcomp 版本中,首先计算赋值的 RHS,然后将其绑定(bind)到 LHS 上的名称。所以
result = [x+[y] for x in result for y in pool]
需要成为
new_result = []
for x in result:
for y in pool:
new_result.append(x+[y])
result = new_result
这样您就不会在迭代时修改 result
。如果您想禁止某些安排——并且您可以按照适用于从左到右填充的迭代顺序的方式编写约束——那么您可以这样做:
def filtered_product(args, filter_fn):
pools = map(tuple, args)
result = [[]]
for pool in pools:
new_result = []
for x in result:
for y in pool:
new_val = x+[y]
if filter_fn(new_val):
new_result.append(x+[y])
result = new_result
print 'intermediate result:', result
for prod in result:
yield tuple(prod)
给出
In [25]: list(filtered_product([[1,2,3], [4,5,6], [7,8,9]], lambda x: sum(x) % 3 != 2))
intermediate result: [[1], [3]]
intermediate result: [[1, 5], [1, 6], [3, 4], [3, 6]]
intermediate result: [[1, 5, 7], [1, 5, 9], [1, 6, 8], [1, 6, 9], [3, 4, 8], [3, 4, 9], [3, 6, 7], [3, 6, 9]]
Out[25]:
[(1, 5, 7),
(1, 5, 9),
(1, 6, 8),
(1, 6, 9),
(3, 4, 8),
(3, 4, 9),
(3, 6, 7),
(3, 6, 9)]
与简单地使用 (p for p in itertools.product(whatever) if condition(p))
相比,这是否会给您带来任何好处将取决于您可以修剪多少分支,因为作为你可以看到它在内存中构造了所有中间列表。
关于python - 如何将 Python 的 itertools.product 库从列表理解转换为普通的 for 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14614004/