Python 当两个不可数中的一个无穷大时,如何得到它们的笛卡尔积

Python 当两个不可数中的一个无穷大时,如何得到它们的笛卡尔积,python,itertools,cartesian-product,Python,Itertools,Cartesian Product,假设我有两个可数,一个是有限的,一个是无限的: import itertools teams = ['A', 'B', 'C'] steps = itertools.count(0, 100) 我想知道是否可以避免嵌套for循环,使用模块中的一个无限迭代器,如cycle或repeat来获得这些iterables的笛卡尔积 循环应该是无限的,因为步骤的停止值在前面是未知的。 预期产出: $ python3 test.py A 0 B 0 C 0 A 100 B 100 C 100 A 20

假设我有两个可数,一个是有限的,一个是无限的:

import itertools

teams = ['A', 'B', 'C']
steps = itertools.count(0, 100)
我想知道是否可以避免嵌套for循环,使用模块中的一个无限迭代器,如
cycle
repeat
来获得这些iterables的笛卡尔积

循环应该是无限的,因为
步骤的停止值在前面是未知的。

预期产出:

$ python3 test.py  
A 0
B 0
C 0
A 100
B 100
C 100
A 200
B 200
C 200
etc...
使用嵌套循环的工作代码:

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()
试一试

正如文档所说,
产品(A,B)
相当于
((x,y)代表A中的x代表B中的y)
。 如您所见,
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)
但您不能将
itertools.product
用于无限循环,因为:

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

导入itertools >>>(itertools.count(2010年)中的年复一年) >>>itertools.产品(itertools.计数(2010)) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 记忆者
itertools.product的输入必须是有限的 不可抗力


对于无限循环,您可以使用。

有一种不使用嵌套循环的方法。基于此,您可以编写以下内容:

from itertools import count, chain, cycle, tee 

teams = ['A', 'B', 'C']
steps = count(0, 100)

for team, step in zip(cycle(teams), chain.from_iterable(zip(*tee(steps, len(teams))))):
    if step == 300:
        break
    print(team, step)
这将给出预期的输出:

$ python3 test.py  
A 0
B 0
C 0
A 100
B 100
C 100
A 200
B 200
C 200
etc...
A 0
B 0
c0
100英镑
B 100
C100
200美元
B200
C 200

它完成了任务,但可读性要差得多。

你能澄清一下你是如何知道何时打破无限循环的吗?当然,“步骤”(偏移量)用于在URL中同时对不同的团队进行API调用,一旦有效负载中的值指示没有“下一个”URL,对于特定团队跳过循环,如果所有团队都是这样,则代码将中断循环。这是一种解决方法,可以使用asyncio并行发出请求,否则每个请求都必须等待来自负载的下一个URL,从而导致按顺序运行。相关:@Georgy您的编辑很好,但接受的答案仅适用于有限iterable。这个问题的答案是有限可数的,如果需要无限可数的问题,应该再问一个问题@DorianTurba我不认为这是一个“变色龙问题”。IIUC,这个问题的第一个版本已经有了无限迭代器的要求,但是,它的表述不够清楚。OP的编辑(第3版)只是明确了这一点。我知道之后的回滚是错误的。
from itertools import count, chain, cycle, tee 

teams = ['A', 'B', 'C']
steps = count(0, 100)

for team, step in zip(cycle(teams), chain.from_iterable(zip(*tee(steps, len(teams))))):
    if step == 300:
        break
    print(team, step)