「いつもソースが長くなってしまう」というアナタ。foreachをLINQで書き換えることから始めてみよう。
見たことはないだろうか? foreachの入れ子、あるいはforeachの後にすぐ別のforeachが来るC#のソースを。foreachクン自体には何の罪もないけれど、ついソースを長くさせてしまう困ったちゃんなのは事実。そこで、foreachをLINQで書き換えてみよう。「今までのあの苦労は何だったんだ……」となること請け合いなスリムアップ効果が期待できる。
準備
ファーストネームとラストネーム、それから年齢を持つPersonなるクラスを定義する。
1 2 3 4 5 6 |
internal class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } |
このクラスのインスタンスを持つPeopleなる配列を準備する。
1 2 3 4 5 6 |
var people = new Person[] { new Person { FirstName = "Ada", LastName = "Smith", Age = 18 }, new Person{ FirstName = "Phil", LastName = "Smith", Age = 20 }, new Person{ FirstName = "Ada", LastName = "Miller", Age = 18 } }; |
さあさあお立ち会い!このpeopleに対する操作をforeachで書いた後、それをLINQにするとどれだけスマート&スリムになるかを紹介する。
ラストネームがSmithの人だけ集める
まずはラストネームがSmithの人(AdaとPhil)だけを集める操作から。foreachで書くとこうなる。
1 2 3 4 5 6 7 8 |
var smithList = new List<Person>(); foreach (var person in people) { if (person.LastName == "Smith") { smithList.Add(person); } } |
これをLINQで書くと……
1 |
var smithList2 = people.Where(person => person.LastName == "Smith"); |
一行!エコですね〜。
Smithのうち老けてる方の年齢を出す
こうして集めたSmith人のうち年かさを増している人の年齢を取得してみよう。例によってforeachから。
1 2 3 4 5 6 7 8 |
int oldAge = -1; foreach (var smith in smithList) { if (smith.Age > oldAge) { oldAge = smith.Age; } } |
これをLINQで書くとこうなる。
1 |
var oldAge2 = smithList2.Max(person => person.Age); |
またもや一行に!
全員の年齢を足す
今度は全員の年齢を足してみよう。まずはforeachバージョン。
1 2 3 4 5 |
int wholeAge = 0; foreach (var person in people) { wholeAge += person.Age; } |
これをLINQで書きなおしてみる。まさかまた一行なんてことは……
1 |
var wholeAge2 = people.Sum(person => person.Age); |
タマラナイね。
最後のAdaだけ取り出す
最後に、ファーストネームがAdaの人のうちpeopleの後の方に入っている人を探してみる。
やっぱりforeachから。
1 2 3 4 5 6 7 8 |
Person lastAda = null; foreach (var person in people) { if (person.FirstName == "Ada") { lastAda = person; } } |
そしてこれがLINQバージョン。
1 |
var lastAda2 = people.LastOrDefault(person => person.FirstName == "Ada"); |
もう当たり前のように短くなるね。
foreachをLINQで書き換えよう
LINQの威力をわかってくれた事と思う。
今回のようなコレクションから要素を取り出すような操作をする場合、取り出した要素を格納しておくための変数を用意し、ループ内で条件判定するのがforeachの定石だ。そこへ来てLINQはというと、すごく大雑把な言い方をするとそれらを一文で書けてしまう。
foreach自体には何の意味もないため、ループ内の処理を見ないと何がしたいかが掴みづらい。LINQはメソッド名を見れば意味が掴めるという良さもある。
foreachに対するLINQの良さはこのように色々あるけれど、すべてのループ処理をLINQで書き換えられるわけではない。ただ、書き換えられるなら劇的にスリムなソースになる。
「ついついソースが長くなってしまって^^;」というアナタは、foreachをLINQで書き換えられないか見直すことから始めてみよう。
更にスマートなC#erになりたいアナタへおすすめのLINQ本