someone's notebook

誰かさんの書いたジャポニカ学習帳

LINQ is Lazy

すごい勘違いをしていたので。

下記のコードでWhere句は何回評価されるか?

var square = Enumerable.Range(0, 10)
    .Where(x => x % 2 == 0)
    .Select(x => x * x);

var sum = 0;
var plusNums = square.Select(x => sum += x);

var a = plusNums.Count();
var b = plusNums.Count();

square.ToList().ForEach(x => Console.WriteLine(x));
Console.ReadKey();

答えは30回。 ちゃんとカウントしてみましょう。

int i = 0;

var square = Enumerable.Range(0, 10)
    .Where(x =>
    {
        i++;
        return x % 2 == 0 ? true : false;
    })
    .Select(x => x * x);

var sum = 0;
var plusNums = square.Select(x => sum += x);

var a = plusNums.Count();
var b = plusNums.Count();

square.ToList().ForEach(x => Console.WriteLine(x));

Console.WriteLine("squareは" + i + "回評価されました。");
Console.ReadKey();

出力結果

0
4
16
36
64
squareは30回評価されました。

すごい処理が遅いなーっと思った処理があって、まさにこれでした。

IEnumerableで返却するとその場では実行されずに遅延評価されます。

そのため、あとから参照した時に何度も呼び出してしまっていました。。


こういう場合は実体化しておく必要があります。

var square = Enumerable.Range(0, 10)
    .Where(x => x % 2 == 0)
    .Select(x => x * x)
    .ToArray();

var sum = 0;
var plusNums = square.Select(x => sum += x);

var a = plusNums.Count();
var b = plusNums.Count();

square.ToList().ForEach(x => Console.WriteLine(x));
Console.ReadKey();

LINQ知ってる人にとっては常識なんだと思うのですが、配列操作が楽ちんくらいのノリで使ってるとダメですね。

出直します。

Fork me on GitHub