LINQのそのForEach、実はSelectで書き換えられるかも


LINQの拡張メソッドとしてよく挙げれるForEach

標準ではIList<T>のみに実装されているのでIEnumerable<T>で使えるように拡張されてる方も多いのではないでしょうか?

実はそのForEachSelectなど他のLINQのメソッドに置き換えられるかもしれません。

例えば(私が)よく見るのは以下のケース。(あまり良い例ではないけど…。)

var list = new List<int>();
var range = Enumerable.Range(0, 10).ForEach(x =>
{
    list.Add(x);
});

とりあえず配列を回して動的配列(List)に詰めるパターン。

これは以下のように書くことができます。

var list = Enumerable.Range(0, 10).ToList();

続いては以下のケース。

var list = new List<int>();
var range = Enumerable.Range(0, 10).ForEach(x =>
{
    var value = x * x;
    list.Add(value);
});

ForEachで回してる値を何か操作してから配列に詰めるパターン。

var list = Enumerable.Range(0, 10).Select(x => x * x).ToList();

これも上記のように書くことができます。

次は以下のようなケース。

var list = new List<int>();
var range = Enumerable.Range(0, 10).ForEach(x =>
{
    if (x % 2 == 0)
        list.Add(x);
});

ループで回してる値を条件によって配列に詰めるパターン。

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

これは上記のように書くことができます。
(更に言えば上記の場合はSelectメソッドも省略できますね。)

どういう時にForEachでなくSelectで出来るかというと、ループで回してる中身に戻り値があるとき、
って憶えておけばいいと思います。

あとはForEach内でif文があるならそれはWhereで代用できます。

逆を言えば戻り値がないとき(void)は通常ループのforeachなりForEachメソッドなり使えばいいと思います。

あとこれまでの例ではListを使ってきましたが、AddRemoveとかしないのであればArrayの方がいいと思います。

下手にListにして知らないうちでデータが足らなくなったとか多くなったとか、読み取り専用でないオブジェクトはバグの始まりだったりするので。