LINQのAverage、Max、Min、Sumについて

# はじめに

　LINQ、超便利ですよね！LINQを使わず書いた6、7行のコードが、LINQを使うことで1行で書くことができます。とても簡潔に、そして読みやすくなりますよね。もう自分はLINQなしでC#のコードを書くのは考えられません。

　この投稿ではAverage、Max、Min、Sumメソッドを紹介します。


## Average、Max、Min、Sumについて

　この投稿では今後、IEnumelable\<T\>のことをT型のシーケンスと呼びます。またこの投稿で、数値型とはint(Int32)、long(Int64)、float(Single)、double(Double)、decimal(Decimal)を指します。

　Average、Max、Min、Sumそれぞれのメソッドでできることは、そのメソッドの名前が表す通りのものです。

* Average:シーケンスの平均値を求める
* Max:シーケンスの最大値を求める
* Min:シーケンスの最小値を求める
* Sum:シーケンスの合計値を求める

　Average、Max、Min、Sumは非常に多くのオーバーロードを持っています。それぞれ各数値型のシーケンスに対してのオーバーロードがあります。また、Nullable\<long\>やNullable\<double\>のように各数値型のnull許容型のシーケンスのオーバーロードを持っています。

　またMaxとMinに関しては、intなどの数値型やそのnull許容型だけでなく、任意の型のシーケンスで呼び出すことが可能です。もしその型がIComparable\<T\>かIComparableを実装している場合、このメソッドはその実装を使用して値を比較した最大値・最小値を得ることが可能です。


　オーバーロードの数が非常に多いので、それぞれを個別に説明することはしません。

## 数値型と(そのnull許容型)のシーケンスの平均値、最大値、最小値、合計値を計算するもの

例えば次のようなコードです。

```csharp:例(1)
double average = new List<int> {0, 1, 2, 3 }.Average (); // 1.5

int? max = new List<int?> {1, 4, 1, null, 4, 2, null, 3, 5, 6}.Max (); // 6

long min = new long[] {2, 2, 3, 4}.Min (); // 2

float sum = new float[] {3.0F ,1.0F, 4.0F, 1.0F, 5.0F, 9.0F, 2.0F}.Sum (); // 25.0F
```

　Average、Max、Min、Sumは、上記のように数値型のシーケンスの平均値、最大値、最小値、合計値を求めます。

## 変換関数を使って、変換した結果を計算するもの

　次のようなRecordClassを使います。

```csharp:RecordClass
public class RecordClass
{
	public int Score { get; set; }
}
```

　引数に変換関数(デリゲート)を渡すオーバーロードです。次のコードではFunc\<Record,int\>を渡しています。recordListの各要素のScoreプロパティに対する平均値、最大値、最小値、合計値を求めています。

```csharp:例(2)
List<RecordClass> recordClassList = GetRecordClassList ();
double average = recordClassList.Average (record => record.Score);
int max = recordClassList.Max (record => record.Score);
int min = recordClassList.Min (record => record.Score);
int sum = recordClassList.Sum (record => record.Score);
```

## 数値型以外のもの(MinとMax)

　数値型以外にも、MinとMaxは任意の型に対して呼び出すことが可能です。もしその型がIComparable\<T\>かIComparableを実装している場合、このメソッドはその実装を使用して値を比較した最大値・最小値を得ることが可能です。

　例を示します。

```csharp:例(3)
List<string> jvmLanguages = new List<string> {
	"Java", "Scala", "Groovy", "Clojure", "JRuby", "Jython", "Kotlin", "Xtend", "Ceylon"
};
Debug.Log (jvmLanguages.Max()); // Xtend
Debug.Log (jvmLanguages.Min()); // Ceylon


TimeSpan[] timeSpans = new TimeSpan[] {
	new TimeSpan(1, 0, 0), new TimeSpan(0, 1, 0), new TimeSpan(0, 0, 1)
};
Debug.Log (timeSpans.Max ()); // 01:00:00
Debug.Log (timeSpans.Min ()); // 00:00:01
```




# シーケンスが空の場合の各メソッドの挙動
## Average

* Average\<int\>などは、要素が空の場合、例外がスローされます。
* Average\<Nullable\<int\>\>などは、シーケンスの要素が空かnull値のみを含む場合、nullを返します。

Funcを引数にとる場合、

* Func\<T, int\>などを引数に取るものは要素が空の場合例外が発生します。
* Func\<T, Nullable\<int\>\>などを引数にとるものは、ソースシーケンスが空かnull値のみを含む場合はnullを返します。

## MaxとMin

* Max\<TSource\>はTSourceが参照型で、シーケンスが空かnull値のみを含む場合、nullを返します。

* Max\<TSource\>はTSourceが値型で、シーケンスが空の場合、例外をスローします。
* Max\<int\>などはシーケンスが空の場合、例外をスローします。
* Max\<Nullable\<int\>\>などはシーケンスが空もしくはnull値のみを含む場合、nullを返します。

Minも同様です。

## Sum

* Sum\<int\>などは要素が含まれない場合は0を返します。
* Sum\<Nullable\<int\>\>などは要素が含まれない場合0を返します。

※ Func系を引数にとるものも同じで0を返します。
※ Nullblle系の返り値型は、Nullable\<int\>型で、nullでなく0値を持っているもの。

# MSDNへのリンク
　MSDNへのリンクを下記に示します。

* [Average](http://msdn.microsoft.com/ja-jp/library/system.linq.enumerable.average(v=vs.110).aspx)
* [Max](http://msdn.microsoft.com/ja-jp/library/system.linq.enumerable.max(v=vs.110).aspx)
* [Min](http://msdn.microsoft.com/ja-jp/library/system.linq.enumerable.min(v=vs.110).aspx)
* [Sum](http://msdn.microsoft.com/ja-jp/library/system.linq.enumerable.sum(v=vs.110).aspx)

# まとめ

　LINQの中でも、Average、Max、Min、Sumは、理解しやすく、使いやすく、利用できそうな場面が多いですよね。

# 補足

　MinやMaxなどこの投稿でとりあげたLINQメソッドは、以前のUnityでは問題がありました。いくつかの条件を満たしてしまった場合、AOTコンパイラの不具合により、iOSなどAOTコンパイルが必要なプラットフォームで実行時例外が発生したのです。

　現在Unityでは、かつてAOTコンパイルが行われていたプラットフォームで、IL2CPPという技術が使われています。

　私が把握している限り、IL2CPPでは本投稿で紹介したメソッドは、問題なく使えているようです。そのため本投稿の記事タイトルを変更し、内容も各メソッドの紹介のみとしました。

　過去の内容を見たい場合は、[編集履歴](http://qiita.com/RyotaMurohoshi/items/d4a6750a7989fa92f81a/revisions)よりご覧ください。