[LINQ][C#] Aggregateの使い方(畳み込み, fold)

[LINQ][C#] Aggregateの使い方(畳み込み, fold)

LINQのAggregateとは

LINQを使った畳み込み(fold)の方法を紹介します。畳み込みにはAggregateを使います。Aggregateは「集約」や「集める」といった意味を持ちます。

Aggregateはどのような処理かというと、シーケンスにアキュムレータ関数を適用する物らしいです。ざっくり言うと

  1. データから1つの要素を取り出し …
  2. 取り出した要素と累積値(アキュムレータ値)を引数にとる関数を実行し …
  3. 累積値(アキュムレータ値)が更新し …
  4. 要素が無くなるまで上記処理を繰り返す

といったような感じです。最終的には累積値(アキュムレータ値)が結果として得られることになります。

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は慣れないうちはわかりづらいですが、使いこなせればかなり応用が効きそうです。

Linqカテゴリの最新記事