今回は、GroupBy拡張メソッドについてです。
GroupBy拡張メソッドは、クエリ式での「group xx by xx.xx」に対応する拡張メソッドです。
LINQでのグルーピングについては、以前の記事で記述していますので、そちらを参照下さればと思います。
- Linq入門記-05 (クエリキーワード, クエリ構文, グルーピング, group, IGrouping
) - Linq入門記-07 (クエリキーワード, クエリ構文, クエリ結果を一時保持, into, select, group, join)
GroupBy拡張メソッドは、オーバーロードが非常に多く、全部で8個あります。
書式は以下の通りです。
public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector ) public static IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer ) public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector ) public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector ) public static IEnumerable<IGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer ) public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector ) public static IEnumerable<TResult> GroupBy<TSource, TKey, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer ) public static IEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer )
大別すると以下のようになります。
- keySelectorのみを指定する版
- keySelectorとelementSelectorを指定する版
- keySelectorとresultSelectorを指定する版
- keySelectorとelementSelectorとresultSelectorを指定する版
注意点として、resultSelectorを指定する版では戻り値が
IEnumerable<IGrouping<TKey, TElement>>
ではなく
IEnumerable<TResult>
となる部分です。
個人的に、resultSelectorを指定する版を利用する事が今の所ほとんどありません。
(実際にresultSelectorを指定する版を処理する場合は、ほぼクエリ式で書いています)
もっぱら利用するのは、keySelectorとelementSelectorを指定する版です。
なので、以下のサンプルではresultSelectorを利用した版は記述してません。m(_ _)m
以下、サンプルです。
#region LinqSamples-25 public class LinqSamples25 : IExecutable { class Person { public int Id { get; set; } public string Name { get; set; } public string Team { get; set; } public string Project { get; set; } public override string ToString() { return string.Format("[ID={0}, NAME={1}]", Id, Name); } } public void Execute() { var persons = new List<Person> { new Person{ Id = 1001, Name = "gsf_zero1", Team = "A", Project = "P1" }, new Person{ Id = 1000, Name = "gsf_zero2", Team = "B", Project = "P1" }, new Person{ Id = 111, Name = "gsf_zero3", Team = "B", Project = "P2" }, new Person{ Id = 9889, Name = "gsf_zero4", Team = "C", Project = "P2" }, new Person{ Id = 9889, Name = "gsf_zero5", Team = "A", Project = "P1" }, new Person{ Id = 100, Name = "gsf_zero6", Team = "C", Project = "P2" } }; // // GroupBy拡張メソッドは、シーケンスの要素をグループ化する際に利用できる。 // クエリ式にて、[group xx by xx.xx]とする場合、実行時にGroupBy拡張メソッドに置き換えられる。 // // 概念としては、SQLのGROUP BYと同じである。 // // GroupBy拡張メソッドには、全部で8つのオーバーロードが存在する。 // よく利用されるのは、以下のものとなると思われる。 // // ・keySelectorのみを指定するもの // ・keySelectorとelementSelectorを指定するもの。 // ・複合キーでのグループ化 // // GroupBy拡張メソッドの戻り値は、 // IEnumerable<IGrouping<TKey, TElement>> // となる。IGroupingインターフェースは、グルーピングを表すインターフェースであり // Keyプロパティが定義されている。 // // このインターフェース自身も、IEnumerableインターフェースを継承しているので // グルーピングを行った場合は、以下のようにして2重のループでデータを取得する。 // // var query = xxx.GroupBy(item => item.Key); // foreach (var group in query) // { // Console.WriteLine(group.Key); // foreach (var item in group) // { // Console.WriteLine(item); // } // } // // // keySelectorのみを指定. // // 以下のクエリ式と同じとなる。 // from thePerson in persons // group thePerson by thePerson.Team // Console.WriteLine("============ keySelectorのみのGroupBy =============="); var query1 = persons.GroupBy(thePerson => thePerson.Team); foreach (var group in query1) { Console.WriteLine("=== {0}", group.Key); foreach (var thePerson in group) { Console.WriteLine("\t{0}", thePerson); } } // // keySelectorとelementSelectorを指定. // // 以下のクエリ式と同じとなる。 // from thePerson in persons // group thePerson.Name by thePerson.Team // Console.WriteLine("\n============ elementSelectorを指定したGroupBy =============="); var query2 = persons.GroupBy(thePerson => thePerson.Team, thePerson => thePerson.Name); foreach (var group in query2) { Console.WriteLine("=== {0}", group.Key); foreach (var name in group) { Console.WriteLine("\t{0}", name); } } // // 複合キーにてグループ化. // // 以下のクエリ式と同じとなる。 // from thePerson in persons // group thePerson by new { thePerson.Project, thePerson.Team } // Console.WriteLine("\n============ 複合キーを指定したGroupBy =============="); var query3 = persons.GroupBy(thePerson => new { thePerson.Project, thePerson.Team }); foreach (var group in query3) { Console.WriteLine("=== {0}", group.Key); foreach (var thePerson in group) { Console.WriteLine("\t{0}", thePerson); } } // // 以下のクエリ式と同じとなる。 // from thePerson in persons // group thePerson by new { thePerson.Project, thePerson.Team } into p // orderby p.Key.Project descending, p.Key.Team descending // select p // Console.WriteLine("\n============ 複合キーとorderbyを指定したGroupBy =============="); var query4 = persons .GroupBy(thePerson => new { thePerson.Project, thePerson.Team }) .OrderByDescending(group => group.Key.Project) .ThenByDescending(group => group.Key.Team); foreach (var group in query4) { Console.WriteLine("=== {0}", group.Key); foreach (var thePerson in group) { Console.WriteLine("\t{0}", thePerson); } } } } #endregion
出力結果は以下のようになります。
============ keySelectorのみのGroupBy ============== === A [ID=1001, NAME=gsf_zero1] [ID=9889, NAME=gsf_zero5] === B [ID=1000, NAME=gsf_zero2] [ID=111, NAME=gsf_zero3] === C [ID=9889, NAME=gsf_zero4] [ID=100, NAME=gsf_zero6] ============ elementSelectorを指定したGroupBy ============== === A gsf_zero1 gsf_zero5 === B gsf_zero2 gsf_zero3 === C gsf_zero4 gsf_zero6 ============ 複合キーを指定したGroupBy ============== === { Project = P1, Team = A } [ID=1001, NAME=gsf_zero1] [ID=9889, NAME=gsf_zero5] === { Project = P1, Team = B } [ID=1000, NAME=gsf_zero2] === { Project = P2, Team = B } [ID=111, NAME=gsf_zero3] === { Project = P2, Team = C } [ID=9889, NAME=gsf_zero4] [ID=100, NAME=gsf_zero6] ============ 複合キーとorderbyを指定したGroupBy ============== === { Project = P2, Team = C } [ID=9889, NAME=gsf_zero4] [ID=100, NAME=gsf_zero6] === { Project = P2, Team = B } [ID=111, NAME=gsf_zero3] === { Project = P1, Team = B } [ID=1000, NAME=gsf_zero2] === { Project = P1, Team = A } [ID=1001, NAME=gsf_zero1] [ID=9889, NAME=gsf_zero5]
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ