LoginSignup
12
9

More than 5 years have passed since last update.

Null許容型でLINQでSumやらAverageするときに注意すべきコト

Last updated at Posted at 2016-10-28

どー言うことか?

IEnumerable<Nullable<T>>に対して、Sum()やらAverage()やら使うと個人的に予想外の結果になったのでその備忘録。

Nullableに関して

NumericなNullableに対して、BinaryOperationを実行した場合、片っぽがnullなら伝播して、結果はnullに成る。


int? x=42;
int? y=114514;
int? z=null;

//114556が出力される。
Console.WriteLine((x + y)?.ToString() ?? "NULL");

//NULLが出力される。
Console.WriteLine((x + z)?.ToString() ?? "NULL");

で、本題

さて、Ienumerable<int?>見たいなシーケンスにSumやらAverageを適用したらどうなるだろうかってのが今日のお題。
Nullが紛れ込んでなきゃ何の問題も無いけど、紛れ込んでいた場合を検証してみた。


int?[] nonNullArray=Enumerable.Range(0,10).Select(x=>(int?)x).ToArray();
int?[] nullArray=nonNullArray.ToArray();
nullArray[9]=null;

int?[] allNullArray=Enumerable.Repeat((int?)null,10).ToArray();

//45
Console.WriteLine(nonNullArray.Sum());

//4.5
Console.WriteLine(nonNullArray.Average());

//9
Console.WriteLine(nonNullArray.Max());

//0
Console.WriteLine(nonNullArray.Min());

Console.WriteLine();

//36
Console.WriteLine(nullArray.Sum());

//4
Console.WriteLine(nullArray.Average());

//8
Console.WriteLine(nullArray.Max());

//0
Console.WriteLine(nullArray.Min());

Console.WriteLine();

//0
Console.WriteLine(allNullArray.Sum());

//null
Console.WriteLine(allNullArray.Average());

//null
Console.WriteLine(allNullArray.Min());

//null
Console.WriteLine(allNullArray.Max());

概ねこんなかんじになる。
以上のことから、

  • 要素にnullが有る場合、フィルタされる。
    • Sum()の場合、nullはフィルタされるので、nullの要素以外の合計となる。
    • Average()の場合、上記の合計をnull以外の要素数で除した結果となる。
    • Min()Max()は不感
  • すべての要素がnullの場合、Sum()は0を返す。
  • Average(),Max(),Min()nullを返す。

まとめ

以上の検証から、nullの要素は基本的にフィルタされて処理されることがわかった。
全要素がnullの場合は、Sum()は0を返し、Sum()以外はnullを返すので、ちょいと注意が必要かと。

要素にnullが存在する場合、結果がnullに成ることを企図したければ、事前にAnyあたりで、当たりを付けるか、Aggregateで処理するか、素直にforeachに展開するが良いかと思います。

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9