1

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

在我的情况下,我正在传递产品功能 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)

任何帮助是极大的赞赏!

4

3 回答 3

4

您非常接近:嵌套列表推导式的右侧的编写顺序与您编写 for 循环的顺序相同,因此您做对了。但是,在 listcomp 版本中,首先计算分配的 RHS,然后将其绑定到 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))取决于您可以修剪多少分支,因为您可以看到它在内存中构造了所有中间列表。

于 2013-01-30T21:49:53.490 回答
3

product 函数通常以归约操作的形式将列表相乘,如果您尝试随时过滤结果,这可能对您没有帮助。相反,您应该编写一个带有固定数量列表的产品函数:

for x in list1:
    for y in list2:
        for z in list3:
            if condition(x, y, z):
                yield tuple(x, y, z)
于 2013-01-30T21:53:32.740 回答
2

请注意,在 , 行result = [x+[y] for x in result for y in pool]result出现了两次,但不相关。此表达式使用旧的 构建一个列表result,然后将这个新列表分配给result

这可能就是让你感到困惑的原因。等效的扩展版本是:

def product(*args):
    pools = map(tuple, args)
    result = [[]]
    for pool in pools:
        tmp = []
        for x in result:   # note that it's the old 'result' here
            for y in pool:
                tmp.append(x+[y])
        result = tmp
    for prod in result:
        yield tuple(prod)
于 2013-01-30T21:49:49.463 回答