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

How to get Cartesian product in Python using a generator?

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

import itertools

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

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

print(iter_tools(*x))

当我尝试相同的代码但使用 return 而不是 yield 时,它工作正常。我怎样才能通过实现生成器来获得笛卡尔积?

如果您想从笛卡尔积中产生单个项目,则需要迭代该产品:

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)

生成器的想法是您不会像在调用时那样同时进行所有计算 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)

您需要什么取决于您的用例。希望我能帮到你:)

最重要的是,itertools.product 已经是一个 iterator. You don't need to write your own. (A generator 是一种迭代器。)例如:

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

现在,解释一下,您似乎误解了一些基本的东西。一个生成器函数returns一个generator iterator。这就是您从印刷品中看到的内容:

>>> 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 强制转换为列表会破坏迭代器的全部目的 - lazy evaluation。如果你真的想从迭代器中产生值,你可以使用 yield from:

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

在这种情况下 iter_tools 毫无意义,但如果您的实际 iter_tools 更复杂,这可能就是您真正想要的。

另请参阅:


此答案部分基于juanpa.arrivillaga's