からのすべての結果を保存せずにこれを行うことは不可能だと思います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
すべての要素を取得し、それらをリストに保存します。次に、すべてのタプルを生成し、それらをmin-heapに格納します。これは、コレクションの最小値のみを抽出することに関心がある場合に効率的なデータ構造です。タプル間の比較は最初の項目の比較から始まるため、並べ替えと同様に、ペア自体を保存せずに、並べ替えたい値 ( ) を先頭に追加するというトリックを実行できます。最後に、すべての要素をヒープからポップして、その合計が次の生成されたペアの合計よりも小さいことが保証され、それらを生成します。genA
b
(a0, b), (a1, b), ..., (a_n, b)
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)]