集合演算用のLINQのメソッド
- LINQで使える集合演算用のメソッドは、Union、Intersect、Exceptの3つです。
- Concatメソッドは、ここでは「和集合(重複データも含まれる)を求める」としていますが、Microsoftのリファレンスを確認すると、「2つのリストを結合する」という処理になっているので、厳密には集合演算用のメソッドとは言えないと思います。
- SQLが分かる方は、LINQのメソッドをSQLの集合演算と比較した方が理解しやすいかもしれません。
- ちなみに、INTERSECT、EXCEPT、MINUSは一部のRDBMSでしか使えません。(※参考資料)
- INTERSECT:Oracle、PostgreSQL
- EXCEPT:PostgreSQL
- MINUS:Oracle
LINQのメソッド | 処理内容 | 対応するSQLの集合演算 |
---|---|---|
Union | 和集合(重複データは除かれる)を求める | UNION |
Concat | 和集合(重複データも含まれる)を求める | UNION ALL |
Intersect | 積集合を求める | INTERSECT |
Except | 差集合を求める | EXCEPT, MINUS |
テストコード1
- 都市の名前が入った2つのリスト(list1, list2)を用意して、それらのリストの和集合、積集合、差集合を求める処理です。
UnitTestSetOperation.cs
[TestClass]
public class UnitTestSetOperation
{
[TestMethod]
public void TestMethod1()
{
List<string> list1 = new List<string>() {"Tokyo", "Osaka", "Yokohama", "Nagoya", "Kobe"};
List<string> list2 = new List<string>() {"Tokyo", "Yokohama", "Sapporo", "Fukuoka"};
// 和集合(重複データは除かれる)
System.Console.WriteLine("和集合(Union):" + string.Join(",", list1.Union(list2)));
// 和集合(重複データも含まれる)
System.Console.WriteLine("和集合(Concat):" + string.Join(",", list1.Concat(list2)));
// 積集合
System.Console.WriteLine("積集合(Intersect):" + string.Join(",", list1.Intersect(list2)));
// 差集合
System.Console.WriteLine("差集合(Except)[list1-list2]:" + string.Join(",", list1.Except(list2)));
System.Console.WriteLine("差集合(Except)[list2-list1]:" + string.Join(",", list2.Except(list1)));
}
}
テストコード1の実行結果
- Exceptメソッドは「レシーバから、引数として指定した変数の内容を引く」という処理なので、レシーバと引数のどちらに設定するかによって結果が変化します。
実行結果
和集合(Union):Tokyo,Osaka,Yokohama,Nagoya,Kobe,Sapporo,Fukuoka
和集合(Concat):Tokyo,Osaka,Yokohama,Nagoya,Kobe,Tokyo,Yokohama,Sapporo,Fukuoka
積集合(Intersect):Tokyo,Yokohama
差集合(Except)[list1-list2]:Osaka,Nagoya,Kobe
差集合(Except)[list2-list1]:Sapporo,Fukuoka
テストコード2
- 都市の名前が入った2つのリスト(list1, list2)を用意して、それらのリストの和集合を作った後、都市名の昇順(あるいは降順)に並べ替える処理です。
- 単なる「リストに対する集合演算」よりも、このような「集合演算+並べ替え」などの複合的な処理が行われるシーンの方が多いかもしれません。
UnitTestSetOperation.cs
[TestMethod]
public void TestMethod2()
{
List<string> list1 = new List<string>() { "Tokyo", "Osaka", "Yokohama", "Nagoya", "Kobe" };
List<string> list2 = new List<string>() { "Tokyo", "Yokohama", "Sapporo", "Fukuoka" };
// 和集合(重複データは除かれる)を求めた後、文字列の昇順にソートする。
System.Console.WriteLine("和集合+昇順:" + string.Join(",", list1.Union(list2).OrderBy(cityName=>cityName)));
// 和集合(重複データは除かれる)を求めた後、文字列の降順にソートする。
System.Console.WriteLine("和集合+降順:" + string.Join(",", list1.Union(list2).OrderByDescending(cityName => cityName)));
}
テストコード2の実行結果
実行結果
和集合+昇順:Fukuoka,Kobe,Nagoya,Osaka,Sapporo,Tokyo,Yokohama
和集合+降順:Yokohama,Tokyo,Sapporo,Osaka,Nagoya,Kobe,Fukuoka
テストコード3
- 「対象差(対象差集合)」とは「Aに属し、Bに属さないもの」と「Bに属し、Aに属さないもの」の両方を合わせた集合なので、和集合と差集合を組み合わせて以下のように実装してみました。
- 対象差をベン図で描くと、排他的論理和と同じ領域で表されます。
UnitTestSetOperation.cs
[TestClass]
public class UnitTestSetOperation
{
[TestMethod]
public void TestMethod3()
{
List<string> list1 = new List<string>() { "Tokyo", "Osaka", "Yokohama", "Nagoya", "Kobe" };
List<string> list2 = new List<string>() { "Tokyo", "Yokohama", "Sapporo", "Fukuoka" };
// 対象差
var set = list1.Except(list2).Union(list2.Except(list1));
System.Console.WriteLine("対象差:" + string.Join(",", set));
}
}
実行結果
対象差:Osaka,Nagoya,Kobe,Sapporo,Fukuoka