最近まで存在を知らなかったSeq.pairwise関数とSeq.windowed関数の紹介をしたいと思います。
Seq.pairwise
引数で渡されたシーケンスを要素数が2のタプルのシーケンスにしてくれます。タプルの生成ルールは、(1番目, 2番目), (2番目, 3番目), (3番目, 4番目)...(n番目, n+1番目)のようになっています。簡単に動きを見てみます。
// 元データ let arr = [| for i = 0 to 5 do yield i |] // pairwiseして配列に let pairwise = Seq.pairwise arr |> Seq.toArray // 元データと結果を表示 printfn "arr = %A" arr printfn "pairwise = %A" pairwise
実行すると以下のようになります。
arr = [|0; 1; 2; 3; 4; 5|] pairwise = [|(0, 1); (1, 2); (2, 3); (3, 4); (4, 5)|]
Seq.windowed
pairwiseが2つずつの組にしていましたが、windowedは任意の数で組を作ってくれます。pairwiseとの違いはpairwiseが本当にTupleを作るのに対してwindowedは、グルーピングした要素を配列にしている点です。恐らく、n番目の要素にアクセスできる機能がTupleに無いせいかな?と個人的に思ってたりします。
これもpairwiseと同じ要領で動きをみてみます。
// 元データ let arr = [| for i = 0 to 5 do yield i |] // windowedして配列に let windowed3 = arr |> Seq.windowed 3 |> Seq.toArray let windowed4 = arr |> Seq.windowed 4 |> Seq.toArray // 元データと結果を表示 printfn "arr = %A" arr printfn "windowed3 = %A" windowed3 printfn "windowed4 = %A" windowed4
実行結果は以下のようになります。こんな関数が標準で用意されてるということは使いでがあるということなんでしょうね。
arr = [|0; 1; 2; 3; 4; 5|] windowed3 = [|[|0; 1; 2|]; [|1; 2; 3|]; [|2; 3; 4|]; [|3; 4; 5|]|] windowed4 = [|[|0; 1; 2; 3|]; [|1; 2; 3; 4|]; [|2; 3; 4; 5|]|]
具体的な使用方法を思いつかない・・・。ここらへん色んなコードを見ないといけないなと思いました。
おまけ
少し前にやったkey, value, key, value ...の順番で値が入ってる配列をDictionary<string, string>に変換するコードはpairwiseを使って以下のように書けます。
// 元データ let arr = [| "key1"; "value1"; "key2"; "value2"; "key3"; "value3" |] let d = arr // pair化 |> Seq.pairwise // indexとpairの組を作って |> Seq.mapi (fun i p -> i, p) // 偶数個めの要素だけ抽出して |> Seq.choose (fun (i, p) -> match i % 2 = 0 with | true -> Some p | _ -> None) // Dictionaryへ変換 |> dict printfn "%A" d
実行結果は以下のような感じです。
seq [[key1, value1]; [key2, value2]; [key3, value3]]
ふむ。いい感じ。
因みに、このやり方はid:taediumさんのBlogのやり方と同じです(if式のところをmatch式にしてみたけど、これならif式のほうが見通しがいいかな・・・)。というか、id:taediumさんのBlogでpairwiseの存在を知った今日この頃でした。