如何使用生成器在Python中获取笛卡尔积?

3

我正在尝试获取多个数组的笛卡尔积,但这些数组非常大,我正在尝试优化内存使用。我尝试使用以下代码实现生成器,但它只返回某个位置存在一个生成器。

import itertools

x = [[1,2],[3,4]]

def iter_tools(*array):
    yield list(itertools.product(*array))

print(iter_tools(*x))

当我尝试使用return而不是yield时,相同的代码可以正常工作。如何实现一个生成器以获得笛卡尔积?


1
你的生成器立即实例化了整个产品,完全打败了它的初衷。无论如何,itertools.product(*array)已经是一个高效的迭代器了。没有必要将其包装在一个生成器中。所以只需使用itertools.product(*array)。你的生成器确实起作用,生成器函数返回生成器。看起来你有一个基本的误解。 - undefined
@juanpa 谢谢!我根据你的评论发布了一个答案 - undefined
3个回答

5

简而言之,itertools.product已经是一个迭代器。你不需要再自己编写一个。(生成器是一种迭代器。)例如:

>>> x = [[1, 2], [3, 4]]
>>> p = itertools.product(*x)
>>> next(p)
(1, 3)
>>> next(p)
(1, 4)

现在,为了解释一下,你似乎误解了一些基本的东西。一个生成器函数返回一个生成器迭代器。这就是你从打印输出中看到的内容:
>>> iter_tools(*x)
<generator object iter_tools at 0x7f05d9bc3660>

使用list()将迭代器转换为列表。
>>> list(iter_tools(*x))
[[(1, 3), (1, 4), (2, 3), (2, 4)]]

注意它是一个嵌套列表。这是因为您的iter_tools生成一个列表,然后没有其他内容。关于这一点,那部分没有意义,因为将itertools.product转换为列表会破坏迭代器的整个目的-惰性评估。如果您实际上想要从迭代器中产生值,您将使用yield from
def iter_tools(*array):
    yield from itertools.product(*array)

在这种情况下,iter_tools 是无意义的,但如果您实际使用的 iter_tools 更复杂,那么这可能是您真正想要的。
另请参阅:

这个答案部分基于juanpa.arrivillaga评论


1
生成器的想法是你不需要像使用list(itertools.product(*array))一样同时进行所有计算。所以你需要一次一个地生成结果。例如,像这样:
def iter_tools(*array):
    for i in array[0]:
        for j in array[1]:
            yield (i, j)


您可以像这样处理每个结果元组:
for tup in iter_tools(*x):
    print(tup)

当然,您可以轻松地调整生成器,使其每次调用产生每一行或每一列。
或者,如果您对itertools提供的内容感到满意:
for i in itertools.product(*x):
    print(i)

你需要的取决于你的使用情况。希望我能帮到你 :)

0
如果你想从笛卡尔积中获取单个项,你需要对该积进行迭代。
import itertools

x = [[1,2],[3,4]]

def iter_tools(*array):
    for a in itertools.product(*array):
        yield a

for a in iter_tools(*x):
    print(a)


1
itertools.product已经是一个迭代器,所以iter_tools就显得毫无意义了。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接