【C#】DataTable でのLINQの使い方（３）

## **はじめに**

前回（[【C#】DataTable でのLINQの使い方（２）](https://qiita.com/HillPaddyField/items/69ab69b3e5f4fa18ab88)）に引き続き、C#のDataTableクラスでLINQを使ったコードを簡単にまとめた内容を記載します。

## 重複行の削除

DataTable で重複している行を削除
※重複行を削除は使う場合は少ないかと、DBから取得する場合は重複行を削除しているかと思うので。

```c#
        DataTable member = new DataTable();
        member.Columns.Add("No", typeof(int));
        member.Columns.Add("Name", typeof(string));
        member.Columns.Add("Age", typeof(int));
        member.Columns.Add("Address", typeof(string));

        member.Rows.Add(1, "太郎", 10, "東京");
        member.Rows.Add(3, "三郎", 30, "大阪");
        member.Rows.Add(1, "太郎", 10, "東京");     // 差異無
        member.Rows.Add(1, "四郎", 10, "東京");     // 差異有
        member.Rows.Add(2, "次郎", 20, "名古屋");

        // 重複行を削除
        DataRow[] rows =
            member.AsEnumerable()
                  .Distinct(DataRowComparer.Default)
                  .ToArray();

        Console.WriteLine("重複する行を削除した結果");
        foreach (DataRow row in rows)
            Console.WriteLine("No:{0},Name:{1},Age:{2},Address:{3}"
                    , row["No"], row["Name"], row["Age"], row["Address"]);

        // 指定項目の重複行を削除
        DataRow[] rows2 =
            member.AsEnumerable()
                  .GroupBy(x => x.Field<int>("No"))
                  .Select(y => y.First())
                  .ToArray();

        Console.WriteLine("指定項目の重複行を削除した結果");
        foreach (DataRow row in rows2)
            Console.WriteLine("No:{0},Name:{1},Age:{2},Address:{3}"
                    , row["No"], row["Name"], row["Age"], row["Address"]);
```

簡単な説明

- 全項目の値が重複している行を削除する場合は「Distinct」を利用する事で削除されます。
  ※サンプルでは「差異無」の行のみが削除されています。

- 項目別で値が重複している行を削除する場合は「GroupBy」を利用する事で削除されます。
  また、削除される行は２行目以降になります。
  ※サンプルでは「No」が重複している「差異無」「差異有」の行が削除されています。

出力結果

> 重複する行を削除した結果
> No:1,Name:太郎,Age:10,Address:東京
> No:3,Name:三郎,Age:30,Address:大阪
> No:1,Name:四郎,Age:10,Address:東京
> No:2,Name:次郎,Age:20,Address:名古屋
>
> 指定項目の重複行を削除した結果
> No:1,Name:太郎,Age:10,Address:東京
> No:3,Name:三郎,Age:30,Address:大阪
> No:2,Name:次郎,Age:20,Address:名古屋



## 複数テーブルでの重複行又は重複行以外の取得

２つのテーブルで重複していない行の取得、又は重複している行の取得

```c#
        DataTable member = new DataTable();
        member.Columns.Add("No", typeof(int));
        member.Columns.Add("Name", typeof(string));
        member.Columns.Add("Age", typeof(int));
        member.Columns.Add("Address", typeof(string));

        member.Rows.Add(1, "太郎", 10, "東京");
        member.Rows.Add(1, "四郎", 10, "東京");     // 差異有
        member.Rows.Add(2, "次郎", 20, "名古屋");
        member.Rows.Add(3, "三郎", 30, "大阪");

        DataTable member2 = new DataTable();
        member2 = member.Clone();

        member2.Rows.Add(1, "太郎", 10, "東京");
        member2.Rows.Add(2, "次郎", 20, "名古屋");
        member2.Rows.Add(3, "五郎", 30, "大阪");     // 差異有

        // 「member」テーブルのみに存在する行を取得
        DataRow[] rows =
            member.AsEnumerable()
                  .Except(member2.AsEnumerable(), DataRowComparer.Default)
                  .ToArray();

        Console.WriteLine("「member」テーブルのみに存在する行を取得した結果");
        foreach (DataRow row in rows)
            Console.WriteLine("No:{0},Name:{1},Age:{2},Address:{3}"
                    , row["No"], row["Name"], row["Age"], row["Address"]);

        // 「member」「member2」テーブル両方に存在する行を取得
        DataRow[] rows2 =
            member.AsEnumerable()
              .Intersect(member2.AsEnumerable(), DataRowComparer.Default)
              .ToArray();

        Console.WriteLine("両テーブルに存在する行を取得した結果");
        foreach (DataRow row in rows2)
            Console.WriteLine("No:{0},Name:{1},Age:{2},Address:{3}"
                    , row["No"], row["Name"], row["Age"], row["Address"]);
```

簡単な説明

- 重複していない行を取得する場合は「Except」を利用する事で取得できます。
  サンプルでは、「member」テーブルで「member2」テーブルのレコードと重複していない行を取得しています。

- 重複している行を取得する場合は「Intersect」を利用する事で取得できます。
  サンプルでは、「member」テーブルと「member2」テーブルのレコードと重複している行を取得しています。

- 今回の方法では項目別の重複には対象できません。

  やり方については別項目で書くと思います。

出力結果

> 「member」テーブルのみに存在する行を取得した結果
> No:1,Name:四郎,Age:10,Address:東京
> No:3,Name:三郎,Age:30,Address:大阪
>
> 両テーブルに存在する行を取得した結果
> No:1,Name:太郎,Age:10,Address:東京
> No:2,Name:次郎,Age:20,Address:名古屋

## おわりに

前回に続きLINQについて書いてみました。
記事を書いている時に思ったのですが、LINQで取得した結果は元のデータとは別の領域に保存されている思うのですが、大量データを処理する場合に領域不足が起きないのか気になりました。
機会が有ればそのあたりも調べてみたいと思います。