配列やリストなどのデータをグループ分けしたい時は無いだろうか?例えば、名前やenum値でインスタンスを分けたいときなど。そんな時に使えるのがLINQのGroupByだ。今回はGroupByの使い方を解説する。
GroupByの考え方
GroupByを使えば、コレクションをキーごとにグループ分けできる。Dictionaryの要素が配列になっているイメージと言ったらわかりやすいだろうか?図にするとこうなる。
ResultがGroupByの返り値であり、その下にKey、更にその下にElementが連なっている。
GroupByの仕様
GroupByの仕様を詳しく見てみよう。いくつかのオーバーロードがあるけれど、ここでは最も簡単なものを見てみる。
1 2 3 |
IEnumerable<IGrouping<TKey, TSource>> GroupBy<Tsource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) |
グループ分けを適用したいコレクション(source)に対して、どのキーで分けるかを指定する(keySelector)。たったこれっぽっちだけれど、IGroupingが何を表しているかが理解しづらいかもしれない。IGroupingは上図で言うとKey 1(あるいはKey 2, Key 3)以下にあたる。
GroupByの使い方1 キーを指定する
それでは実際にGroupByを使ってグループ分けをしてみよう。名前と年齢を持つPersonなるクラスを考え、そのインスタンスを複数抱えるコレクション・Peopleを作る。
1 2 3 4 5 6 7 |
var people = new Person[] { new Person { Name = "Sato", Age = 25 }, new Person { Name = "Suzuki", Age = 30 }, new Person { Name = "Sato", Age = 27 }, new Person { Name = "Tanaka", Age = 27 } }; |
これを名前が同じ者同士で分けてみるとこうなる。
1 |
var nameGroupedPeople = people.GroupBy(person => person.Name); |
クエリ形式だとこうだ。
1 2 3 |
var nameGroupedPeople = from person in people group person by person.Name; |
nameGroupedPeopleの中身はこのような構造になる。
これを年齢でグループ分けするならこうだ。
1 |
var ageGroupedPeople = people.GroupBy(person => person.Age); |
これもクエリで表せられる。byの後につづいてグループ分けに使うもの(=年齢)を指示している。
1 2 3 |
Group by age"]var ageGroupedPeople = from person in people group person by person.Age; |
GroupByの使い方2 要素を指定する
グループの要素(図の一番右にあたる)の形式を指定することもできる。例えば先ほどのPeopleの例で、同じ名前の人の年齢だけを取り出したい時はこうする。
1 2 3 |
var nameGroupedAges = people.GroupBy( person => person.Name, person => person.Age); |
クエリだとこうだ。groupの後につづいて年齢だけを取り出すことを指定しているのが分かる。
1 2 3 |
var nameGroupedAges = from person in people group person.Age by person.Name; |
C#のロングセラー学習書
C#以外の言語でも役に立つ名著