发电机与其自身的产物

时间:2017-07-20 04:43:16

标签: python python-3.x

我需要迭代生成器的产品,不包括对角线。我尝试使用itertools.tee两次使用相同的生成器

def pairs_exclude_diagonal(it):
    i1, i2 = itertools.tee(it, 2)
    for x in i1:
        for y in i2:
            if x != y:
                yield (x, y)

这不起作用

In [1]: for (x, y) in pairs_exclude_diagonal(range(3)):
   ...:     print(x, y)
0 1
0 2

documentation for tee州:

  

从单个可迭代中返回n个独立迭代器。

这样做的正确方法是什么?

(我使用的是python3.6.1)

2 个答案:

答案 0 :(得分:4)

您似乎想要使用itertools.permutations

In [1]: import itertools

In [2]: for x, y in itertools.permutations(range(3), 2):
   ...:     print(x, y)
   ...:     
0 1
0 2
1 0
1 2
2 0
2 1

如果确实希望使用tee进行操作,则必须将第二个迭代变为list,以便第二次通过时不会耗尽外for循环:

In [14]: def pairs_exclude_diagonal(it):
    ...:     i1, i2 = itertools.tee(it, 2)
    ...:     l2 = list(i2)
    ...:     for x in i1:
    ...:         for y in l2:
    ...:             if x != y:
    ...:                 yield (x, y)
    ...:                 

In [15]: for (x, y) in pairs_exclude_diagonal(range(3)):
    ...:     print(x, y)
    ...:     
0 1
0 2
1 0
1 2
2 0
2 1

请注意,这是毫无意义的,因为在迭代器上调用list会将其加载到内存中,并且首先无法使用迭代器。

答案 1 :(得分:1)

问题在于您尝试重用i2迭代器。在它被迭代一次之后,它已经筋疲力尽,所以你不能再次迭代它。当你尝试时,它什么都不产生。

我认为而不是tee(这对于此目的来说效率不高),你应该使用itertools.product来生成所有对(在过滤掉你想要跳过的对之前):

def pairs_exclude_diagonal(it):
    for x, y in itertools.product(it, repeat=2):
        if x != y:
            yield (x, y)