如何使用生成器在 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
我正在尝试获取多个数组的笛卡尔积,但数组非常大,我正在尝试优化内存使用。我尝试使用下面的代码实现一个生成器,但只是 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