ここではLINQ to Objectについてまとめます。
List<string>のリスト要素に対して、特定の要素を抽出したり、
全ての要素に処理を施す場合、どのように書くのでしょうか。
LINQの使えない言語を使っていると、以下のようなforeachを普通に書いてしまいます。
List<Stage> stages = new List<Stage>();
//stagesはStageクラスのリストとする
foreach (stage in stages) {
//抽出条件1
//抽出条件2
...
//抽出結果に対する処理
}こう書いてしまうと、抽出条件と結果に対する処理が入り混じって、
非常に読みづらいコードになりがちです。
仕様の追加や変更で条件分岐が増えていって・・・
となるともはや画面に収まりきらないforeach文になったりします。
これをLINQを使って書いてみます。
List<Stage> stages = new List<Stage>();
//stagesはStageクラスのリストとする
var filtered = stages
.Where(stage => {条件式1})
.Where(stage => {条件式2});
foreach (stage in filtered) {
//抽出結果に対する処理
}これだと、抽出条件をまとめて適用した処理と、
抽出結果に対する処理が明確に分かれており、
修正が必要な箇所をすぐに突き止めることができそうです。
このように配列やリストの属性を持ったオブジェクトに対して、
抽出や射影といった処理を施し、結果をまとめることができます。
ここではLINQの拡張メソッドである抽出の機能について書きます。
上記で使った抽出機能はWhereでしたが、他にも様々な拡張メソッドが用意されています。
特定の要素を1つに抽出する場合、指定した要素がなければ例外を送出しますが、
OrDefaultが付く場合は型の規定値が返るようになります。
List<Stage> stages = new List<Stage>();
//stagesはStageクラスのリストとする
/*
指定したインデックスにある要素を抽出します。
*/
var filtered = stages.ElementAt(1);
var filtered = stages.ElementAtOrDefault(1);
/*
最初の要素を抽出します。
*/
var filtered = stages.First();
var filtered = stages.FirstOrDefault();
/*
最後の要素を抽出します。
*/
var filtered = stages.Last();
var filtered = stages.LastOrDefault();
/*
リスト要素が単一の場合にそれを返します。
単一でなければ例外、もしくは規定値を返します。
*/
var filtered = stages.Single();
var filtered = stages.SingleOrDefault();
/*
条件式を満たす要素を全て抽出します。
*/
var filtered = stages.Where(stage => stage.id == 1);
/*
重複を除いた要素を全て抽出します。
*/
var filtered = stages.Distinct();
/*
先頭から指定数飛ばした後、残りの要素を全て抽出します。
*/
var filtered = stages.Skip(1);
/*
先頭から条件式を満たす要素を飛ばし、
満たさない要素以降の全ての要素を抽出します。
*/
//stage.idが3以降の要素を全て抽出する。
var filtered = stages.SkipWhere(stage => stage.id != 3);
/*
先頭から指定数分の要素を抽出します。
*/
var filtered = stages.Take(3);
/*
先頭から条件式を満たす要素を抽出します。
条件を満たさない要素が現れた時、それ以降の要素は処理されません。
*/
//stage.idが3でない要素を抽出し、3が現れたら抽出を終える。
var filtered = stages.TakeWhere(stage => stage.id != 3);