|
|
連載:[完全版]究極のC#プログラミング
Chapter15 LINQとクエリ式
川俣 晶
2010/03/17 |
|
|
15.18 join句の左外部結合
グループ化結合は上記のように二重の繰り返しを必要とする。これは、ある商品を販売している店舗一覧を知りたい場合には便利だが、単に「商品」と「販売店」の組み合わせリストだけがほしい場合は冗長である。
そこで、さらにクエリ式にfrom句をもう1つ追加することで、二重の繰り返しを再度単層の繰り返しに変換させることができる(リスト15.22参照)。
using System;
using System.Linq;
class Program
{
class 商品情報
{
public int Id;
public string 名前;
}
class 商品販売価格
{
public int Id;
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=4, 名前="COMKIT 8060" },
};
商品販売価格[] 商品販売価格データ =
{
new 商品販売価格() { Id=1, 店名="BitOut" },
new 商品販売価格() { Id=1, 店名="富士山音響" },
new 商品販売価格() { Id=2, 店名="富士山音響" },
new 商品販売価格() { Id=3, 店名="マイコンセンターROM" },
new 商品販売価格() { Id=3, 店名="富士山音響" },
};
var query = from x in 商品情報データ
join y in 商品販売価格データ
on x.Id equals y.Id into z
from a in z
select new { Name = x.名前, 販売店 = a };
foreach (var 商品 in query)
{
Console.WriteLine("{0}", 商品.Name);
Console.WriteLine("\t{0}", 商品.販売店.店名);
}
}
}
|
|
リスト15.22 単層の繰り返し |
PC-8001
BitOut
PC-8001
富士山音響
MZ-80K
富士山音響
Basic Master Level-3
マイコンセンターROM
Basic Master Level-3
富士山音響
|
|
リスト15.22の実行結果 |
つまり、「列挙」である範囲変数zをさらにfrom句で個々の値に分解することで、select句は列挙を含まない結果を生成することができ、結果として二重の列挙を発生させないで済む。
しかし、このコードには1つだけ決定的な不満がある。それは、join句の右側に対応する項目(店名)がない左側の項目(名前)は出力されないことである。この例では、「COMKIT 8060」という名前が実行結果にまったく出てこない。
この問題を解決する結合が、「左外部結合」である。対応する要素がない場合でも、左側のすべての種類の要素を得ることができる。
方法は簡単で、「DefaultIfEmptyメソッド」をfrom句に追加するだけである(リスト15.23参照)。
var query = from x in 商品情報データ
join y in 商品販売価格データ on x.Id equals y.Id into z
from a in z.DefaultIfEmpty(
new 商品販売価格() { 店名 = "取り扱い店なし" })
select new { Name = x.名前, 販売店 = a };
|
|
リスト15.23 左外部結合の例(クエリ式以外はリスト15.7と同様のため省略) |
PC-8001
BitOut
PC-8001
富士山音響
MZ-80K
富士山音響
Basic Master Level-3
マイコンセンターROM
Basic Master Level-3
富士山音響
COMKIT 8060
取り扱い店なし
|
|
リスト15.23の実行結果 |
DefaultIfEmptyメソッドはSystem.Linq.EnumerableクラスからIEnumerable<TSource>に対して提供される拡張メソッドである。指定されたシーケンスを受け取ってそのまま返すが、シーケンスが空の場合に限って、その型のデフォルト値または引数で指定されたデフォルト値を返す。デフォルト値は、引数なしで使えば型のデフォルト値(int型なら0、クラスならnullなど)が使われる。引数を記述すれば、それがデフォルト値になる。
この例では、
new 商品販売価格() { 店名 = "取り扱い店なし" }
|
|
というデフォルト値を指定している。
これにより、対応関係が存在しない要素にはこのデフォルト値が補われ、左側の要素はすべて出力される。
ちなみに、DefaultIfEmptyメソッドの引数にデフォルト値を書き込まず、結果にnullを含めさせるのも1つの方法である。対応する要素がない場合に複雑な処理を実行する必要があるときは、nullを返して、それをチェックするほうが処理しやすいこともある。
Insider.NET 記事ランキング
本日
月間