当其中一个是无限的时如何获得两个迭代的笛卡尔积

HTF*_*HTF -1 python cartesian-product python-itertools

假设我有两个可迭代对象,一个是有限的,一个是无限的:

import itertools

teams = ['A', 'B', 'C']
steps = itertools.count(0, 100)
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以避免嵌套的 for 循环并使用itertools模块中的无限迭代器之一,例如cyclerepeat来获取这些迭代器的笛卡尔积。

循环应该是无限的,因为 的停止值steps预先未知。

预期输出:

$ python3 test.py  
A 0
B 0
C 0
A 100
B 100
C 100
A 200
B 200
C 200
etc...
Run Code Online (Sandbox Code Playgroud)

带有嵌套循环的工作代码:

from itertools import count, cycle, repeat

STEP = 100 
LIMIT = 500
TEAMS = ['A', 'B', 'C']


def test01():
    for step in count(0, STEP):
        for team in TEAMS:
            print(team, step)
        if step >= LIMIT:  # Limit for testing
            break

test01()
Run Code Online (Sandbox Code Playgroud)

tom*_*mjn 5

尝试 itertools.product

from itertools import product
for i, j in product(range(0, 501, 100), 'ABC'):
    print(j, i)
Run Code Online (Sandbox Code Playgroud)

正如文档所说product(A, B),相当于((x,y) for x in A for y in B). 如您所见,product产生一个元组,这意味着它是一个生成器并且不会在内存中创建列表以正常工作。

这个函数大致相当于下面的代码,只不过实际的实现不会在内存中建立中间结果:

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)
Run Code Online (Sandbox Code Playgroud)

但是itertools.product由于已知问题,您不能使用无限循环:

根据文档, itertools.product 相当于生成器表达式中的嵌套 for 循环。但是, itertools.product(itertools.count(2010)) 不是。

>>> import itertools
>>> (year for year in itertools.count(2010))
<generator object <genexpr> at 0x026367D8>
>>> itertools.product(itertools.count(2010))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError
Run Code Online (Sandbox Code Playgroud)

itertools.product 的输入必须是有限迭代的有限序列。

对于无限循环,您可以使用此代码