先日TOACHで紹介したLINQの入門記事は、おかげさまで多くの人に読んでもらえたようだ。
Hello LINQ world. 野暮ったいC#コードから卒業したいアナタへ。LINQ 基本の4つ。
このLINQの第一歩では、Any、Select、Where、FirstOrDefaultという4つの基本的なメソッドを紹介した。
今回は、もう少し込み入ったことをするときに使えるメソッドを説明したい。
重複を取り除く -Distinct-
配列中の重複している要素を刈り込んで、ユニークな要素だけにしてくれるサッパリメソッド。
作例では、[0, 1, 2, 2, 3, 4] なる”2″が重複している配列にDistinctをかけ、[0, 1, 2, 3, 4]という重複のない状態にしている。
1 2 3 4 |
var numbers = new[] { 0, 1, 2, 2, 3, 4 }; // This contains [0, 1, 2, 3, 4] var distinctedNumbers = numbers.Distinct(); |
もちろん、数値以外にもこのメソッドは使える。
例えば、”c”が重複している配列を考えてみよう。この場合もほうらこのとおり。
1 2 3 4 |
var texts = new[] { "a", "b", "c", "c" }; // This contains ["a", "b", "c"] var distinctedTexts = texts.Distinct(); |
無事に “a”, “b”, “c”なる配列を取得できた。
配列をDictionaryへ -ToDictionary-
配列やListからDictionaryを作るとき、もしかしてこんなコードを書いていないだろうか?
1 2 3 4 5 6 7 |
var numbers = new[] { 0, 1, 2, 3, 4 }; var dictionary = new Dictionary<int, int>(); foreach (var number in numbers) { dictionary[number] = number; } |
これは、数値配列をDictionaryへ変換するコードだけれど、こんなに単純なことをするためにこんなに行を費やす必要はない。LINQならこうなるのでR。
1 2 3 4 5 |
var numbers = new[] { 0, 1, 2, 3, 4 }; var linqDictionary = numbers.ToDictionary( number => number, number => number); |
ToDictionary()の第一引数のラムダ式でDictionaryのキーを指定し、第二引数ではその値を決めている。
これを使うと、自作クラスを収めた配列をDictionary化するときなんかに威力が発揮される。
例えば、名前と年齢を持ったPersonというクラスを考える。
1 2 3 4 5 |
class Person { public string Name { get; set; } public int Age { get; set; } } |
このクラスのインスタンスがいくつか入った配列を、名前をキーに、年齢をその値としたDictionaryを作りたい場合はこうなる。
1 2 3 4 5 6 7 8 9 10 |
var persons = new[] { new Person { Name = "John", Age = 40 }, new Person { Name = "Yoko", Age = 82 }, new Person { Name = "Sean", Age = 40 } }; var namedDictionary = persons.ToDictionary( person => person.Name, person => person.Age); |
キーとしてperson.Name、値としてperson.Ageを指定するだけの簡単工法。手抜きではありません。
昇順/降順に並べる -OrderBy, OrderByDescending-
最後に、Personインスタンスを年齢を基に昇順(年齢が高いほど後ろへ)と降順に並べる方法を見てみよう。
1 2 3 4 5 |
// 昇順 The order is 40 -> 40 -> 82 var ascendingPersons = persons.OrderBy(person => person.Age); // 降順 The order is 82 -> 40 -> 40 var descendingPersons = persons.OrderByDescending(person => person.Age); |
たった一行で年齢順にPersonを並べることができる。
大したことはしていないけれど、これをforループでやると地味に面倒な処理になってしまう。
大したことない処理を大したことない実装で実現する。まるで英語を読んでいるかのようにスラスラと。
それがLINQの目指すものなのかもしれない。
LINQの豊富な実用例を知りたい人にはこれがオススメ