LINQのGroupByメソッドって使ってますか?コレクションの要素をグループに分類する場合に簡潔に記述することができて便利です。この記事では、LINQのGroupByメソッドについて
- GroupByメソッドとは
- GroupByメソッドの使い方
- OrderByメソッドとは
- OrderByメソッドとはの使い方
- 複数のキーを指定する方法
など基本的な内容から、応用的な使い方の内容についても解説していきます。今回はLINQのGroupByメソッドについて、使い方をわかりやすく解説します!
GroupByメソッドとは
LINQのGroupByメソッドは、コレクションの要素をグループに分類する場合に使用します。ちなみにLINQとはコレクション(配列やList、Dictionaryなど)の要素を処理するメソッドを集めたライブラリです。
LINQのGroupByメソッドを使うと、コレクションの要素をグループに分類する処理を簡潔に記述することができます。
GroupByの使い方
GroupByメソッドはコレクションのオブジェクトから呼び出して使うことができます。GroupByメソッドの引数にはラムダ式でグループ分けのKeyを指定します。ラムダ式とは、一言で言うとメソッドを変数と同様に扱う記述様式になります。
ラムダ式の基本構文は以下のようになります。
左辺 => 右辺
左辺には、メソッドの変数を指定します。パラメータは「( )」で囲む必要がありますが、変数が1つのみの場合は「( )」を省略することができます。変数が複数の場合は、各変数を「,」(カンマ)で区切ります。
() => 右辺 // 変数なしの場合 param => 右辺 // 変数が1つの場合 (param1, param2) => 右辺 // 変数が2つの場合
変数の型はコンパイラによって自動的に推論されます。必要であれば型を指定することもできます。
(int param) => 右辺 // 変数をint型で指定
それではGroupByソッドの使い方について、サンプルコードで確認しましょう。GroupByメソッドを使うため、usingディレクティブを使ってSystem.Linqを参照しています。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result.GroupBy(x => x.Subj); foreach(var group in query) { Console.WriteLine(group.Key); foreach(var item in group) { Console.WriteLine("{0}:{1}点", item.Name, item.Points); } } Console.ReadKey(); } } }
実行結果:
国語 田中 一郎:90点 鈴木 二郎:60点 佐藤 三郎:70点 数学 田中 一郎:80点 鈴木 二郎:50点 佐藤 三郎:80点 英語 田中 一郎:70点 鈴木 二郎:80点 佐藤 三郎:90点
このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ―変数Subjの値でグループ分けをしています。
複数のキーを指定する
グループ分けのキーを複数個指定することもできます。GroupByメソッドの引数でnew句を使って複数指定します。サンプルコードで確認しましょう。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result.GroupBy(x => new {Subj = x.Subj, ClassName = x.ClassName}); foreach(var group in query) { Console.WriteLine(group.Key); foreach(var item in group) { Console.WriteLine("{0}:{1}点", item.Name, item.Points); } } Console.ReadKey(); } } }
実行結果:
{ Subj = 国語, ClassName = A } 田中 一郎:90点 鈴木 二郎:60点 { Subj = 数学, ClassName = A } 田中 一郎:80点 鈴木 二郎:50点 { Subj = 英語, ClassName = A } 田中 一郎:70点 鈴木 二郎:80点 { Subj = 国語, ClassName = B } 佐藤 三郎:70点 { Subj = 数学, ClassName = B } 佐藤 三郎:80点 { Subj = 英語, ClassName = B } 佐藤 三郎:90点
このサンプルコードでは、GroupByメソッドの引数にnew句を使って複数のキーを設定しています。
Whereで条件を指定する
GroupByメソッドでグループに分ける際に、Whereオペレータを使って条件を絞ることもできます。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result .Where(x => x.Points < 70) .GroupBy(x => x.Subj); foreach(var group in query) { Console.WriteLine(group.Key); foreach(var item in group) { Console.WriteLine("{0}:{1}点", item.Name, item.Points); } } Console.ReadKey(); } } }
実行結果:
国語 鈴木 二郎:60点 数学 鈴木 二郎:50点
このサンプルコードでは、Whereオペレータを使ってTestクラスのメンバ変数Pointsの値が70未満の要素のみグループ分けしています。
Sumで合計値を求める
集計演算子を使ってグループ分けした結果の値を集計演算することができます。ここでは集計演算子Sumを使ってグループ分けした結果の合計値を求める方法をご紹介します。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result .GroupBy(x => x.Name) .Select(x => new {Name = x.Key, Sum = x.Sum(y => y.Points)}); foreach(var group in query) { Console.WriteLine("{0}の合計点数:{1}点", group.Name, group.Sum); } Console.ReadKey(); } } }
実行結果:
田中 一郎の合計点数:240点 鈴木 二郎の合計点数:190点 佐藤 三郎の合計点数:240点
このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ変数Nameの値でグループ分けを行っています。さらにグループ分けした結果に対して、集計演算子Sumを使ってTestクラスのメンバ変数Pointsの値の合計値を算出しています。
Countで数を数える
ここでは集計演算子Countを使ってグループ分けした結果の要素数を求める方法をご紹介します。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result .Where(x => x.Points <= 70) .GroupBy(x => x.Subj) .Select(x => new {Subj = x.Key, Count = x.Count()}); foreach(var group in query) { Console.WriteLine("{0}で70点以下:{1}人", group.Subj, group.Count); } Console.ReadKey(); } } }
実行結果:
英語で70点以下:1人 国語で70点以下:2人 数学で70点以下:1人
このサンプルコードでは、GroupByメソッドを使ってTestクラスのメンバ変数Subjの値でグループ分けを行っています。Whereオペレータを使ってTestクラスのメンバ変数Pointsの値が70以下の要素に条件を絞っています。
さらに集計演算子Countを使ってグループ分け後の要素数を算出しています。
OrderByメソッドとは
LINQのOrderByメソッドは、コレクションの要素を並び替える場合に使用します。
OrderByの使い方
OrderByメソッドはコレクションのオブジェクトから呼び出して使うことができます。OrderByメソッドの引数にはラムダ式で並び替えのKeyを指定します。
昇順に並び替える場合はOrderByメソッドを使用し、降順に並び替える場合はOrderByDescendingメソッドを使用します。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result .OrderByDescending(x => x.Points) .GroupBy(x => x.Subj); foreach(var group in query) { Console.WriteLine(group.Key); foreach(var item in group) { Console.WriteLine("{0}:{1}点", item.Name, item.Points); } } Console.ReadKey(); } } }
実行結果:
国語 田中 一郎:90点 佐藤 三郎:70点 鈴木 二郎:60点 英語 佐藤 三郎:90点 鈴木 二郎:80点 田中 一郎:70点 数学 田中 一郎:80点 佐藤 三郎:80点 鈴木 二郎:50点
このサンプルコードでは、OrderByDescendingメソッドを使ってTestクラスのメンバ変数Pointsの値で降順に並び替えています。
複数のキーを指定する
複数のキーを指定して並び替えることもできます。第2キー以降で昇順に並び替える場合はThenByメソッドを、降順に並び替える場合はThenByDescendingメソッドを使います。
using System; using System.Collections.Generic; using System.Linq; namespace Sample { class Test { public string Subj { get; set; } public int Points { get; set; } public string Name { get; set; } public string ClassName { get; set; } } class Sample { static void Main() { var result = new List<Test>() { new Test {Subj = "国語", Points = 90, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "数学", Points = 80, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "英語", Points = 70, Name = "田中 一郎", ClassName = "A"}, new Test {Subj = "国語", Points = 60, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "数学", Points = 50, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "英語", Points = 80, Name = "鈴木 二郎", ClassName = "A"}, new Test {Subj = "国語", Points = 70, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "数学", Points = 80, Name = "佐藤 三郎", ClassName = "B"}, new Test {Subj = "英語", Points = 90, Name = "佐藤 三郎", ClassName = "B"}, }; var query = result .OrderByDescending(x => x.Points) .ThenBy(x => x.Name) .GroupBy(x => x.Subj); foreach(var group in query) { Console.WriteLine(group.Key); foreach(var item in group) { Console.WriteLine("{0}:{1}点", item.Name, item.Points); } } Console.ReadKey(); } } }
実行結果:
英語 佐藤 三郎:90点 鈴木 二郎:80点 田中 一郎:70点 国語 田中 一郎:90点 佐藤 三郎:70点 鈴木 二郎:60点 数学 佐藤 三郎:80点 田中 一郎:80点 鈴木 二郎:50点
このサンプルコードでは、OrderByDescendingメソッドを使ってTestクラスのメンバ変数Pointsの値で降順に並び替えています。さらにThenByメソッドを使ってTestクラスのメンバ変数Nameの値で昇順に並び替えています。
数学にグループ分けされた要素の並び順が変わっています。
まとめ
ここでは、LINQのGroupByメソッドやOrderByメソッドについて説明しました。コレクションの要素をグループ分けする場合に簡潔に記述することができます。使いこなすことができるように、この記事を何度も参考にして下さいね!