はじめに
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許容型)のシーケンスの平均値、最大値、最小値、合計値を計算するもの
例えば次のようなコードです。
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を使います。
public class RecordClass
{
public int Score { get; set; }
}
引数に変換関数(デリゲート)を渡すオーバーロードです。次のコードではFunc<Record,int>を渡しています。recordListの各要素のScoreプロパティに対する平均値、最大値、最小値、合計値を求めています。
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を実装している場合、このメソッドはその実装を使用して値を比較した最大値・最小値を得ることが可能です。
例を示します。
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へのリンクを下記に示します。
まとめ
LINQの中でも、Average、Max、Min、Sumは、理解しやすく、使いやすく、利用できそうな場面が多いですよね。
補足
MinやMaxなどこの投稿でとりあげたLINQメソッドは、以前のUnityでは問題がありました。いくつかの条件を満たしてしまった場合、AOTコンパイラの不具合により、iOSなどAOTコンパイルが必要なプラットフォームで実行時例外が発生したのです。
現在Unityでは、かつてAOTコンパイルが行われていたプラットフォームで、IL2CPPという技術が使われています。
私が把握している限り、IL2CPPでは本投稿で紹介したメソッドは、問題なく使えているようです。そのため本投稿の記事タイトルを変更し、内容も各メソッドの紹介のみとしました。
過去の内容を見たい場合は、編集履歴よりご覧ください。