LoginSignup
34
23

【C#】和集合、積集合、差集合、対象差を求める

Last updated at Posted at 2019-01-31

集合演算用の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

参考URL

34
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
23