简体   繁体   English

如何懒惰地生成和处理来自生成器的结果组合?

[英]How can I lazily generate and process combinations of results from a generator?

I have a generator, and I'd like to perform a nested loop on it in such a way that the inner loop will start from where the outer loop stands at the moment.我有一个生成器,我想在它上面执行一个嵌套循环,这样内部循环将从当前外部循环所在的位置开始。 For example, I have a generator that produces the list [1,2,3] , and my loop should produce: (1,2),(1,3),(2,3) .例如,我有一个生成列表[1,2,3]的生成器,我的循环应该生成: (1,2),(1,3),(2,3) The code I came up with is the following:我想出的代码如下:

from itertools import tee

def my_gen():
    my_list = [1, 2, 3]
    for x in my_list:
        yield  x

first_it = my_gen()
while True:
    try:
        a = next(first_it)
        first_it, second_it = tee(first_it)
        for b in second_it:
            print(a,b)
    except StopIteration:
        break

This code is cumbersome, not efficient and does not look very pythonic to me.这段代码很麻烦,效率不高,对我来说看起来不是很pythonic。 Please notice that I cannot use combinations_with_replacement because I need an inner loop for processing a specific value from the outer loop.请注意,我不能使用combinations_with_replacement ,因为我需要一个内部循环来处理来自外部循环的特定值。

Any suggestions for a more elegant and pythonic code?对更优雅和 Pythonic 代码有什么建议吗?

The repeated cloning and exhausting of only one of the resulting iterators is not very efficient.只重复克隆和耗尽生成的迭代器之一不是很有效。 As per the itertools.tee docs :根据itertools.tee文档

In general, if one iterator uses most or all of the data before another iterator starts, it is faster to use list() instead of tee().一般来说,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,那么使用 list() 而不是 tee() 会更快。

from itertools import islice

my_list = [1, 2, 3]
# or, more generally
# my_list = list(my_gen())

for i, a in enumerate(my_list):
    for b in islice(my_list, i+1, None):
        print((a, b))
(1, 2)
(1, 3)
(2, 3)

The result (1,2),(1,3),(2,3) isn't the cartesian product.结果(1,2),(1,3),(2,3)不是笛卡尔积。 Do you mean to obtain all the combinations without repetition?您的意思是无需重复即可获得所有组合?

For combinations without repetition对于没有重复的组合

Use itertools.combinations function:使用itertools.combinations函数:

from itertools import combinations

print(list(combinations([1,2,3], 2)))

For actual cartesian product对于实际的笛卡尔积

Using list comprehension you can reduce your code into a more pythonic and elegant way:使用列表推导,您可以将代码简化为更 Pythonic 和优雅的方式:

my_list = [1, 2, 3]

c_prod = [(i, j) for i in iter(my_list) for j in iter(my_list)]

print(c_prod)

Another choice is to use the itertools.product function:另一种选择是使用itertools.product函数:

import itertools

for i in itertools.product(my_list, my_list):
    print(i)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM