LINQのAggregateとは
LINQを使った畳み込み(fold)の方法を紹介します。畳み込みにはAggregateを使います。Aggregateは「集約」や「集める」といった意味を持ちます。
Aggregateはどのような処理かというと、シーケンスにアキュムレータ関数を適用する物らしいです。ざっくり言うと
- データから1つの要素を取り出し …
- 取り出した要素と累積値(アキュムレータ値)を引数にとる関数を実行し …
- 累積値(アキュムレータ値)が更新し …
- 要素が無くなるまで上記処理を繰り返す
といったような感じです。最終的には累積値(アキュムレータ値)が結果として得られることになります。
Aggregateの使い方
Aggregateは少し難しいように感じますが、例を見たほうがわかりやすいはずです。
var src = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
var sum = src.Aggregate((n, elem) => n + elem); // 45
var cnt = src.Aggregate((count, elem) => count + 1); // 10
Console.WriteLine(string.Format("Sum:{0}, Count:{1}", sum, cnt));
ここでは配列の中の数値の合計と個数を求めています。関数の引数がそれぞれ、累積値と要素になり、その戻り値が次の1つ目の引数に与えられます。
ただしこのあたりのよく使われる処理はLINQ側であらかじめ用意されています。
var src = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
var sum = src.Sum();
var cnt = src.Count();
Console.WriteLine(string.Format("Sum:{0}, Count:{1}", sum, cnt));
初期値(Seed)がある場合のAggregate
Aggregateには初期値(最初のアキュムレータ値)を与えることができます。初期値を指定しない場合、最初の要素が初期値となるようです。
var src = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
var sum = src.Aggregate(100, (n, elem) => n + elem);
ここでは合計値を求めていますが、初期値に100を与えてるため、100に0~9を足した145が結果として得られます。初期値を指定しない場合は最初の要素の0が初期値となり、これに1~9までの要素がたされることとなります。
つまり初期値を指定しない場合、アキュムレータ関数の呼び出し回数が1回少なくなります。
下記例では配列の中身を結合していますが、呼び出される関数(アキュムレータ関数)の中で引数の内容を出力しています。初期値(最初のアキュムレータ値)に空文字を与えた場合は”あ”~”お”までの5回アキュムレータ関数が呼び出され順次結合される様子が確認できます。しかし初期値を与えない場合、最初の要素”あ”が初期値となっています。
var data = new[] {"あ","い","う","え","お"};
var d = data.Aggregate("", (str, elem) => {
Console.WriteLine(string.Format("str:{0}, elem:{1}", str, elem));
return str + elem;
});
Console.WriteLine(d);
Aggregateは慣れないうちはわかりづらいですが、使いこなせればかなり応用が効きそうです。
コメントを書く