for WPF developers
Home Profile Tips 全記事一覧

GroupJoin 拡張メソッドでシーケンスを連結してグループ化する

(2017/03/08 18:04:28 created.)

(2017/03/13 8:34:49 modified.)

GroupJoin 拡張メソッドは 2 つの関連するシーケンスを連結しながらグルーピングします。例えば次のような 2 つの表を考えてみましょう。

個人別テーブル

個人 ID 名前
1 田中
2 鈴木
3 佐藤

作業別テーブル

作業 ID 個人 ID 作業時間
1 1 2
2 3 4
3 1 1
4 2 3
5 3 2
6 1 2

一方は個人に ID を割り振り、その番号から名前が特定できるようになっています。もう一方は作業 ID からどれだけの時間がかかっているかを特定できるようになっており、その担当者を個人 ID で把握しています。これらのテーブルから、個人ごとの作業時間を集計する場合に GroupJoin 拡張メソッドが効果的です。 次のサンプルコードで GroupJoin 拡張メソッドの動作を確認してみましょう。

Program.cs
  1. namespace Tips_Linq
  2. {
  3.     using System;
  4.     using System.Linq;
  5.  
  6.     class Program
  7.     {
  8.         static void Main(string[] args)
  9.         {
  10.             var table1 = new [] {
  11.                 new { ID = 1, Name = "田中" },
  12.                 new { ID = 2, Name = "鈴木" },
  13.                 new { ID = 3, Name = "佐藤" },
  14.             };
  15.             var table2 = new [] {
  16.                 new { ID = 1, PersonalID = 1, Quantity = 2 },
  17.                 new { ID = 2, PersonalID = 3, Quantity = 4 },
  18.                 new { ID = 3, PersonalID = 1, Quantity = 1 },
  19.                 new { ID = 4, PersonalID = 2, Quantity = 3 },
  20.                 new { ID = 5, PersonalID = 3, Quantity = 2 },
  21.                 new { ID = 6, PersonalID = 1, Quantity = 2 },
  22.             };
  23.  
  24.             var table = table1.GroupJoin(table2, x => x.ID, y => y.PersonalID, (x, y) => new { Key = x, Values = y });
  25.             foreach (var t in table)
  26.             {
  27.                 Console.WriteLine("== {0} さん ====", t.Key.Name);
  28.                 foreach(var value in t.Values)
  29.                 {
  30.                     Console.WriteLine("作業 ID = " + value.ID + ", 時間 = " + value.Quantity);
  31.                 }
  32.             }
  33.  
  34.             Console.ReadKey();
  35.         }
  36.     }
  37. }


このように GroupJoin 拡張メソッドを使うことで、元となる個人別テーブルの情報から、関連テーブルである作業別テーブルをグルーピングすることができます。入力引数ごとに詳しく見ていきましょう。

第 1 引数には関連テーブルを指定します。ここでは作業別テーブルを指定するため、table2 を指定しています。

第 2 引数と第 3 引数には元となるテーブルと関連テーブルを紐付けるキーをそれぞれ指定します。ここでは、元となるテーブルである個人別テーブルの個人 ID と、関連テーブルである作業別テーブルの個人 ID によって紐付けたいため、第 2 引数では table1 の ID プロパティを、第 3 引数では table2 の PersonalID プロパティを指定しています。

第 4 引数では出力シーケンスをどのように整形するかを指定します。その入力として元となるテーブルのひとつの要素に対して、関連テーブルに紐づけられた複数のデータを扱います。上記のサンプルコードではラムダ式の変数 x が元となるテーブルのひとつの要素、y が紐づけられた複数のデータとなっています。ここでは Key プロパティと Values プロパティを持つ匿名クラスを出力シーケンスの要素としています。

図で表すと次のようになります。


2 つのテーブルを紐付けるそれぞれのキーが等しいかどうかを比較するとき、特に指定がない場合は既定の等値比較演算子が使われます。カスタムクラスなどを比較するときに等値比較演算子を指定する場合は第 5 引数として指定することができます。等値比較演算子については「Distinct 拡張メソッドで重複する要素をシーケンスから除外する」を参照してください。