C#でコレクションを左外部結合してみた
C#で、自分で定義したクラスのコレクションを、LINQを使って左外部結合してみました。
目次
左外部結合とは
2つのテーブルの列の値が同じレコードと、列の値が一致しない左側のテーブルのレコードを取得するものです。左外部結合とかleft outer joinとかでググると、たくさん説明が出てきます。
LINQ を使うと、コレクションに対して左外部結合ができます。
コレクション(A)とコレクション(B)の左外部結合をする場合のクエリは、こんな感じです。
var query = from 変数名(A) in コレクション(A)
join 変数名(B) in コレクション(B)
on 変数名(A).比較するプロパティ equals 変数名(B).比較するプロパティ into コレクション(C)
from 変数名(C) in コレクション(C).DefaultIfEmpty(new コレクション(B)のクラス {右側の要素が無い場合の規定値})
select new {プロパティ = 変数名(A).プロパティ, プロパティ = 変数名(C).プロパティ};
コレクション(A)が左側のテーブル、コレクション(B)が右側のテーブル、コレクション(C)はデータを一時的に格納するところです。コレクション(C)は事前に定義する必要はありません。
DefaultIfEmpty()というメソッドがありますが、これはnullのときに返す規定値を指定するものです。つまり、右側のテーブルがnullのときの規定値をここで指定します。
括弧内に何も指定しなければnullが返ります。ただし、その後ろのselectのところで変数名(C)を参照していたりすると、エラーになります。
試してみた
この2つのテーブルを、左外部結合してみます。 EDLINのところに注目です。
テーブルはそれぞれCSVファイルにして、 TextFieldParser で読み込みます。
コードはこんな感じにしました。
using System;
using System.Linq;
using System.Collections.ObjectModel;
using Microsoft.VisualBasic.FileIO;
namespace trial_linq
{
class Program
{
static void Main(string[] args)
{
// 結合するコレクション
Collection<RelationEditorOs> RelationTable = new Collection<RelationEditorOs>();
Collection<OSList> OSLists = new Collection<OSList>();
// 1つめのテーブルの読み込み
TextFieldParser parser = new TextFieldParser("relation_editor_os.csv", System.Text.Encoding.GetEncoding("Shift_JIS"));
using (parser)
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.CommentTokens = new string[] { "#" };
parser.HasFieldsEnclosedInQuotes = true;
parser.TrimWhiteSpace = true;
while (!parser.EndOfData)
{
string[] row = parser.ReadFields();
RelationEditorOs rel = new RelationEditorOs();
rel.ID = int.Parse(row[0]);
rel.EditorName = row[1];
rel.EditorID = int.Parse(row[2]);
rel.OSID = int.Parse(row[3]);
RelationTable.Add(rel);
}
}
// 2つめのテーブルの読み込み
TextFieldParser parser2 = new TextFieldParser("os_table.csv", System.Text.Encoding.GetEncoding("Shift_JIS"));
using (parser)
{
parser2.TextFieldType = FieldType.Delimited;
parser2.SetDelimiters(",");
parser2.CommentTokens = new string[] { "#" };
parser2.HasFieldsEnclosedInQuotes = true;
parser2.TrimWhiteSpace = true;
while (!parser2.EndOfData)
{
string[] row = parser2.ReadFields();
OSList rel = new OSList();
rel.ID = int.Parse(row[0]);
rel.OsName = row[1];
rel.IssureID = int.Parse(row[2]);
OSLists.Add(rel);
}
}
// クエリ
var query = from p in RelationTable
join q in OSLists on p.OSID equals q.IssureID into r
from s in r.DefaultIfEmpty(new OSList {IssureID = -1, OsName = "N/A" })
select new { EditorName = p.EditorName, OSID = p.OSID, OSTableID = s.IssureID, OSName = s.OsName };
// クエリの実行と出力
Console.WriteLine("Editor\tOS ID\tIssure\tOS Name");
foreach (var s in query)
{
string str = string.Empty;
str = s.EditorName + "\t" + s.OSID + "\t" + s.OSTableID + "\t" + s.OSName;
Console.WriteLine(str);
}
}
public class RelationEditorOs
{
public int ID { get; set; }
public string EditorName { get; set; }
public int EditorID { get; set; }
public int OSID { get; set; }
}
public class OSList
{
public int ID { get; set; }
public string OsName { get; set; }
public int IssureID { get; set; }
}
}
}
クエリ以外のところは、 内部結合のとき とほぼ同じです。
出力結果はこうなりました。
表にするとこんな感じです。
(注意:秀丸、MeryのMS-DOS版やMSX版はありません。VimもMSX版はたぶんありません。EDLINはMS-DOS用のエディタです。)
EDLINが、内部結合では削除されましたが、左外部結合のときには出力されています。
公開日
広告
C#でデータ処理カテゴリの投稿
- C#でDataAdapterを使ってAccessのデータベースを読み書きしてみた
- C#でDataAdapterを使ってAccessのデータベースを読み書きしてみた(OleDb編)
- C#でDataGridに表示するデータを操作してみた
- C#でDataTableのカラムのデータ型を読んでみた
- C#でDataTableの自動インクリメントをしてみた
- C#でJSON形式のデータを出力してみた
- C#でLinq to objectの結果をDataTableにしてみた
- C#でSQLite3のデータベースを使ってみる(ADO.NET ファクトリーデザインパターン)
- C#でSQLiteを使ってみる(インストール)
- C#でコレクションの要素の数を調べる
- C#でコレクションを内部結合してみた
- C#でコレクションを左外部結合してみた
- C#でコレクションを昇順または降順に並び替える
- C#で渡された配列を加工して配列で返す関数について注意すること
- C#のキューを試してみた
- C#のスタックを試してみた