我有两个生成器genA
和genB
,每个生成器生成一个无限的,严格单调递增的整数序列。
现在我需要一个生成所有元组(a, b)
的生成器,a
生成genA
,b
生成genB
a < b
},由a + b
升序排序。如果不明确,则排序并不重要,即如果a + b == c + d
,则首先生成(a, b)
或先生成(c, d)
无关紧要。
例如。如果genA
和genB
都生成素数,则新生成器应生成:
(2, 3), (2, 5), (3, 5), (2, 7), (3, 7), (5, 7), (2, 11), ...
如果genA
和genB
是有限列表,则压缩然后排序就可以了。
对于(x, b)
格式的所有元组,以下内容适用:first(genA) <= x <= max(genA,b) <= b
,first(genA)
genA
生成的第一个元素和生成的最后一个元素max(genA,b)
genA
小于b
。
这是我走了多远。关于如何以所描述的方式组合两个发电机的任何想法?
答案 0 :(得分:2)
我不认为可以在不保存genA
的所有结果的情况下执行此操作。解决方案可能如下所示:
import heapq
def gen_weird_sequence(genA, genB):
heap = []
a0 = next_a = next(genA)
saved_a = []
for b in genB:
while next_a < b:
saved_a.append(next_a)
next_a = next(genA)
# saved_a now contains all a < b
for a in saved_a:
heapq.heappush(heap, (a+b, a, b)) #decorate pair with sorting key a+b
# (minimum sum in the next round) > b + a0, so yield everything smaller
while heap and heap[0][0] <= b + a0:
yield heapq.heappop(heap)[1:] # pop smallest and undecorate
说明:主循环仅对genB
中的所有元素进行迭代,然后从genA
获取小于b
的所有元素,并将它们保存在列表中。然后它生成所有元组(a0, b), (a1, b), ..., (a_n, b)
并将它们存储在min-heap中,当您只想提取集合的最小值时,这是一种有效的数据结构。与排序一样,您可以执行trick不保存对本身,但在它们前面添加您要排序的值(a+b
),因为元组之间的比较将通过比较第一项来开始。最后,它弹出堆中的所有元素,其总和保证小于为下一个b
生成的任何对的总和并产生它们。
请注意,在生成结果时,heap
和saved_a
都会增加,我想与目前生成的元素数量的平方根成比例。
快速测试一些素数:
In [2]: genA = (a for a in [2,3,5,7,11,13,17,19])
In [3]: genB = (b for b in [2,3,5,7,11,13,17,19])
In [4]: for pair in gen_weird_sequence(genA, genB): print pair
(2, 3)
(2, 5)
(3, 5)
(2, 7)
(3, 7)
(5, 7)
(2, 11)
(3, 11)
(2, 13)
(3, 13)
(5, 11)
(5, 13)
(7, 11)
(2, 17)
(3, 17)
(7, 13)
正如所料。使用无限生成器进行测试:
In [11]: from itertools import *
In [12]: list(islice(gen_weird_sequence(count(), count()), 16))
Out[12]: [(0, 1), (0, 2), (0, 3), (1, 2), (0, 4), (1, 3), (0, 5), (1, 4),
(2, 3), (0, 6), (1, 5), (2, 4), (0, 7), (1, 6), (2, 5), (3, 4)]