連載:[完全版]究極のC#プログラミング

Chapter15 LINQとクエリ式

川俣 晶
2010/03/17
Page 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

15.17 join句のグループ化結合

 join句には「内部結合」のほかに、「グループ化結合」と「左外部結合」が存在する。続けて、この2つを見ていこう。

 内部結合は、2つのソースに一致する値を見い出した時点で、続きのクエリを発動できた。たとえば、「ID番号と商品名を持つソース」と「ID番号と価格を持つソース」を使い、ID番号で内部結合を行えば、商品名とそれに対応する価格を結び付けることができた。

 しかし、この機能は場合によっては十分ではない。同じ商品を異なる店舗で別の価格で販売している場合、商品名に対する価格は複数になってしまう。さらに、価格ごとに「どの店での値段か」という情報も添えなければならない。

 このようなケースでは、「内部結合」ではなく「グループ化結合」を使用するとよい。グループ化結合は、join句で結合の対象となる2つのソースのうち、左側のソースの要素が、右側のソースに含まれる1つ以上の一致する要素に関連付けられる

 つまり、このケースでは次のような関連付けが行われる。

商品名 => ((店名, 価格), (店名, 価格), ……)

 実際にこれを記述した例を、次ページのリスト15.21に示す。

using System;
using System.Linq;

class Program
{
  class 商品情報
  {
    public int Id;
    public string 名前;
  }

  class 商品販売価格
  {
    public int Id;
    public int 価格;
    public string 店名;
  }

  static void Main(string[] args)
  {
    商品情報[] 商品情報データ =
    {
      new 商品情報() { Id = 1, 名前="PC-8001" },
      new 商品情報() { Id = 2, 名前="MZ-80K" },
      new 商品情報() { Id = 3, 名前="Basic Master Level-3" },
    };

    商品販売価格[] 商品販売価格データ =
    {
      new 商品販売価格() {Id=1, 価格=168000, 店名="BitOut"},
      new 商品販売価格() {Id=1, 価格=148000, 店名="富士山音響"},
      new 商品販売価格() {Id=2, 価格=178000, 店名="富士山音響"},
      new 商品販売価格() {Id=3, 価格=298000, 店名="マイコンセンターROM"},
      new 商品販売価格() {Id=3, 価格=229000, 店名="富士山音響"},
    };

    var query = from x in 商品情報データ
                join y in 商品販売価格データ
                                  on x.Id equals y.Id into z
                select new { Name = x.名前, 商品データ = z };

    foreach (var 商品 in query)
    {
      Console.WriteLine("{0}", 商品.Name);

      foreach (var 価格情報 in 商品.商品データ)
      {
        Console.WriteLine("\t{0} {1:C}",
                                価格情報.店名, 価格情報.価格);
      }
    }
  }
}
リスト15.21 グループ化結合の例

PC-8001
    BitOut \168,000
    富士山音響 \148,000
MZ-80K
    富士山音響 \178,000
Basic Master Level-3
    マイコンセンターROM \298,000
    富士山音響 \229,000
リスト15.21の実行結果

 このように、1つの商品名に対して、複数の「店名+価格」情報が関連付けられた。

 さて、「内部結合」では次の書式が使用された。

join 〜 in 〜 on 〜 equals 〜
join句による内部結合の構文

 これに対して、グループ化結合では次のように「intoキーワード」が追加されてさらに長くなる(この“into”はinto句ではなく、join-into構文と呼ばれるものの一部。厳密には、join句には、intoを持たないjoin構文とjoin-into構文の2種類が存在する)。

join 〜 in 〜 on 〜 equals 〜 into 〜
join句によるグループ化結合の構文

 intoキーワードの役割は、equalsキーワードで指定された条件を満たす右側のソースの要素をグループ化することである。左側のソースの要素が同じものごとに、グループ分けが行われる。

 たとえば、リスト15.21では「into z」と書かれているが、このzにグループ分けされたグループが格納されている。これはselect句によって、「商品データ = z」のように参照して利用できる。実際、次のforeach文で利用されている。

foreach (var 価格情報 in 商品.商品データ)

 つまり、グループ化結合は、グループごとに結合された値の集まりを列挙する。すべて列挙するには、階層化された二重の繰り返し(列挙)を必要とする。このようにすれば、(リスト15.21の)実行結果に見られるような階層化された結果を得るために使用できる。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter15 LINQとクエリ式
    1.15.1 LINQの面白さ
    2.15.2 LINQとは何か?
    3.15.3 「値の集まり」に対する演算
    4.15.4 なぜLINQなのか?
    5.15.5 最も基本的なLINQ
    6.15.6 LINQの本質は列挙
    7.15.7 LINQを使ううえでの注意点
    8.15.8 クエリ結果を加工する
    9.15.9 複数のソースからクエリする
    10.15.10 条件で絞り込む
    11.15.11 一部項目のみselectする
    12.15.12 シンプルなソート
    13.15.13 クエリの接続
    14.15.14 クエリ結果のグループ化
    15.15.15 複数ソースを関連付けるjoin句
    16.15.16 from句とjoin句のパフォーマンス
  17.15.17 join句のグループ化結合
    18.15.18 join句の左外部結合
    19.15.19 単独で使うDefaultIfEmptyメソッド
    20.15.20 内部列挙を伴うfrom句の二重使用
    21.15.21 let句
    22.15.22 クエリのインスタンス化
    23.15.23 クエリ結果の個数を得る
    24.15.24 Anyメソッドと存在チェック/【C#olumn】クエリ式のデバッグテクニック
    25.15.25 まとめ/【C#olumn】LINQの難しさ/【Exercise】練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間