[C#] Aggregateを使う[LINQ]


C#のAggregateを使い方メモです(((o(*゚▽゚*)o))) 私書かないとすぐ忘れるので!><
Aggregateを利用すると、独自の集計処理を行う事ができます! 汎用的な集計関数, みたいなイメージですね(((o(*゚▽゚*)o))) 実際, これで簡単に sum 関数などを定義できます.
難しい言葉で言うと, “シーケンス(IEnumerable 実装クラス)にアキュムレータ関数を適用するもの” です.

{操作したいリスト}.Aggregate(関数)

で, 値を得ることができます.

このメソッド, 初期値(seed)を与える版のオーバーロードもあるのですが, それは(Haskellの)畳み込みの関数っぽいなあと思いました.

いつものおことわり

これはプログラミング初学者の *日記* です! 技術系記事ではありません!(書きたくても書けない.) すみません><
初心者はこういうことを考えてるんだなあという参考になったらさいわいです

辞書で引いてみた

Aggregate を英和辞書で引いてみました(((o(*゚▽゚*)o)))

aggregate
【動詞】 【他動詞】
〈…を〉集合する,集める,集団とする.
【自動詞】
1. 集まる.
2.〔+補語〕総計〈…と〉なる.

(引用元: weblio )

なるほど!(((o(*゚▽゚*)o))) Aggregate は『集める』とか『統計となる』とかいう意味らしい(((o(*゚▽゚*)o)))へぇ〜! (←英語できない英文科卒)

まず真っ先に気になるのが型ですよね!

Haskell風に型を書くと

Aggregate :: (IEnumerable a b) => (a -> b -> b) -> [a] -> b

ってなるのかなあ? >< すごーーーーーく自信無いっ

とくに, 公式ドキュメント読んだら, パラメータの型は

型: System.Collections.Generic.IEnumerable<TSource>

(引用元: http://msdn.microsoft.com/ja-jp/library/vstudio/bb548651(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1 )
って書いてあって, 全然分からなくてヽ(;▽;)ノ Enumerable って名前の型クラスっぽい何かなのかなと勝手に推測してそれを元に上の表記(Enumerable a b という型クラス制約)で書きました.

——- 追記 (2014/12/2) ——-
twitter で教えていただきました!ヽ(;▽;)ノ

なるほどです!

Aggregate :: (a -> a -> a) -> IEnumerable a -> a

ですね!(((o(*゚▽゚*)o))) ありがとうございます!

sum 関数と product 関数の動作を書く

サンプルとして, sum 関数と product 関数の動作を書きました(((o(*゚▽゚*)o)))
using System.Linq;
してから書きます!

// Aggregate 対象となるリスト
var list = new [] {1, 2, 3, 4, 5};
        
var sum  = list.Aggregate((n, next) => n + next);
// 15

var product = list.Aggregate((n, next) => n * next);
// 120
{操作したいリスト}.Aggregate(関数);
list.Aggregate((w, next) => w + next);

ですね(((o(*゚▽゚*)o)))

あっ, わざわざ書くことじゃない(見れば分かるものな)んですけど, 一応!

((n, next) => n + next)

は, ラムダ式です!

Haskell で書くと

(\ n next -> n + next)

ってなりますね!

中身

Aggregate は 『シーケンスにアキュムレータ関数を適用する』ものだってマイクロソフトの公式ドキュメントに書いてありました.
でも難しい言葉で私にはサッパリ分かりませんでしたヽ(;▽;)ノ

なのでコードで見たらわかりやすいと思いました(((o(*゚▽゚*)o)))

list.Aggregate(func); は、以下のコードと同じ結果を得ます!
(コード引用元: ++C++;// 未確認飛行 C 『C# によるプログラミング入門』 )

static T Aggregate<T>(IEnumerable<T> list, Func<T, T, T> func)
{
  var acc = default(T);
  foreach (var x in list)
  {
    acc = func(acc, x);
  }
  return acc;
}

わかりやすいです!(((o(*゚▽゚*)o)))
foreach のなかで, 引数で与えられた関数にどんどん要素を順番に適用していますね

初期値 (seed) を与える版のAggregate

上のやつは初期値与えないやつなんですけど, 今度は初期値を与える版のやつを書きます(((o(*゚▽゚*)o)))

sum 関数と product 関数の動作を書く

var sum     = new [] { 1, 2, 3, 4, 5 }
                .Aggregate(0, (n, next) => n + next); 
// 15

var product = new [] { 1, 2, 3, 4, 5 }
                .Aggregate(1, (n, next) => n * next); 
// 120

ってなりますね!(((o(*゚▽゚*)o))) 上に書いたサンプルと同じ動作をしています.

{操作したいリスト}.Aggregate(初期値, 関数)

という使い方です(((o(*゚▽゚*)o)))

だから, 和を求めるときは初期値は0 (0にどんどん足していくから) なので,
.Aggregate(0, (n, next) => n + next);
と, 初期値を0として第一引数に与えています.

同じく, すべての要素の積を求めるときは, 初期値は1 (もし0にしたら何をかけても0なので悲しいことになってしまう) なので, 第一引数に 1 を与えています
.Aggregate(1, (n, next) => n * next);

おわり

ところで明日誕生日なのです₍₍⁽⁽(ી(*゚▽゚*)ʃ)₎₎⁾⁾ノリノリ!
₍₍⁽⁽(ી(*゚▽゚*)ʃ)₎₎⁾⁾ノリノリ!
23歳です!₍₍⁽⁽(ી(*゚▽゚*)ʃ)₎₎⁾⁾ノリノリ!素数!₍₍⁽⁽(ી(*゚▽゚*)ʃ)₎₎⁾⁾ノリノリ!
明日の予定は, 会社行って, 歯医者さん行って, 『関数型プログラミング実践入門』を読みます₍₍⁽⁽(ી(*゚▽゚*)ʃ)₎₎⁾⁾ノリノリ!
この本めっちゃ良いですよ! すごく面白いです!! おととい購入してからずっと読んでいます!