シーケンスを使用すると、遅延関数によってシーケンスにオーバーヘッドが追加されます。同じシーケンスで Seq.skip を何千回も呼び出すと、明らかに遅くなります。
Seq.zip
またはを使用Seq.map2
して、一度に 2 つのシーケンスを処理できます。
> Seq.map2 (+) [1..3] [10..12];;
val it : seq<int> = seq [11; 13; 15]
Seq モジュールが十分でない場合は、独自の関数を作成する必要がある場合があります。あなたがやろうとしていることを理解しているかどうかはわかりませんが、このサンプル関数が役立つかもしれません:
let fct (s1: seq<_>) (s2: seq<_>) =
use e1 = s1.GetEnumerator()
use e2 = s2.GetEnumerator()
let rec walk () =
// do some stuff with the element of both sequences
printfn "%d %d" e1.Current e2.Current
if cond1 then // move in both sequences
if e1.MoveNext() && e2.MoveNext() then walk ()
else () // end of a sequence
elif cond2 then // move to the next element of s1
if e1.MoveNext() then walk()
else () // end of s1
elif cond3 then // move to the next element of s2
if e2.MoveNext() then walk ()
else () // end of s2
// we need at least one element in each sequence
if e1.MoveNext() && e2.MoveNext() then walk()
編集 :
前の関数は Seq モジュールの機能を拡張することを意図していたので、おそらくそれを高階関数にしたいと思うでしょう。ildjarn が言ったように、LazyList を使用するとコードがきれいになります。
let rec merge (l1: LazyList<_>) (l2: LazyList<_>) =
match l1, l2 with
| LazyList.Cons(h1, t1), LazyList.Cons(h2, t2) ->
if h1 <= h2 then LazyList.cons h1 (merge t1 l2)
else LazyList.cons h2 (merge l1 t2)
| LazyList.Nil, l2 -> l2
| _ -> l1
merge (LazyList.ofSeq [1; 4; 5; 7]) (LazyList.ofSeq [1; 2; 3; 6; 8; 9])
しかし、データの反復を処理から分離する必要があると思います。反復する高階関数を作成するのは良い考えです (最終的には、反復子関数のコードで変更可能な列挙子を使用しても問題ありません)。