かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Seq.pairwiseとSeq.windowed

最近まで存在を知らなかった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の存在を知った今日この頃でした。