python - 如何将 Python 的 itertools.product 库从列表理解转换为普通的 for 循环?

标签 python for-loop list-comprehension python-itertools

根据 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/

相关文章:

javascript - 我想使用 for 循环来获取 jquery 中复选框和文本框的 id

c++ - Range-for-loops 和 std::vector<bool>

python - 简单的python列表理解

python - 使用 pandas 读取文本文件时格式化列

python - 如何将一个数据框中的每个值连接到另一个数据框中的每一行?

python - 如何使用cherrpy内置的数据存储

python - 用空格分隔相邻相同字符的递归函数

c - Makefile -std=c99 错误

python - 列表理解从元组列表构建嵌套字典

python - 如何编写列表理解,包括 If Else 条件