はじめに:「和集合」は“全部まとめて、ダブりは1つにする”技
業務でデータを扱っていると、こういう場面がよく出てきます。
「A システムと B システムのユーザーを“全部”見たい」
「複数ファイルに分かれているコードを“まとめて一覧”にしたい」
「権限 A と権限 B を持つユーザーの“どちらかに含まれる人すべて”を対象にしたい」
こういう「両方の要素を全部集めるけれど、同じものは1回でいい」というのが、集合でいう「和集合」です。
C# / LINQ では Union を使うことで、和集合をシンプルに書けます。
ここから、初心者向けに
和集合のイメージUnion の基本(値型・string)
オブジェクトでの和集合
実務での和集合の使いどころ
を、例題付きでかみ砕いて説明していきます。
和集合のイメージをつかむ
A ∪ B とは「A と B のどちらかにあるもの全部」
集合の世界で A ∪ B(A ユニオン B)は、
「A にあるものと B にあるものを全部集めて、同じものは1回にまとめたもの」
という意味です。
例えば、
A = {1, 2, 3}
B = {3, 4, 5}
なら、A ∪ B = {1, 2, 3, 4, 5} です。
3 は両方にありますが、結果では1回だけ出てきます。
LINQ の Union は、この「A ∪ B」をそのままやってくれるメソッドです。
基本:数値・文字列の和集合を Union で求める
int の和集合
まずは一番シンプルな例から。
using System;
using System.Collections.Generic;
using System.Linq;
var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 3, 4, 5 };
var union = a.Union(b).ToList();
Console.WriteLine(string.Join(", ", union)); // 1, 2, 3, 4, 5
C#ここでの重要ポイントは、「a.Union(b) は“a と b の要素を全部集めて、重複を1つにまとめる”」ということです。Concat との違いがとても大事です。
var concat = a.Concat(b).ToList(); // 1, 2, 3, 3, 4, 5
C#Concat は「ただくっつけるだけ」、Union は「くっつけたあと、同じ値を1つにまとめる」という違いがあります。
string の和集合(コード一覧を統合する)
商品コードの一覧を統合するイメージで見てみます。
var codesFromSystemA = new[] { "A001", "A002", "A003" };
var codesFromSystemB = new[] { "A003", "A004" };
var allCodes = codesFromSystemA.Union(codesFromSystemB).ToList();
Console.WriteLine(string.Join(", ", allCodes)); // A001, A002, A003, A004
C#「どちらかのシステムに存在するコードを全部知りたい」というときに、Union がぴったりです。
ここでの重要ポイントは、「和集合は“どちらかに含まれていれば対象”という考え方」だということです。
積集合(Intersect)が「両方にあるもの」、差集合(Except)が「片方にだけあるもの」、
和集合(Union)は「どちらかにあるもの全部」です。
オブジェクトの和集合:何をもって「同じ」とみなすか
そのまま Union すると「参照が同じかどうか」になる
クラスのリストに対して Union を使うときは注意が必要です。
public class User
{
public string Id { get; set; } = "";
public string Name { get; set; } = "";
}
C#var list1 = new List<User>
{
new User { Id = "U001", Name = "Sato" },
new User { Id = "U002", Name = "Suzuki" },
};
var list2 = new List<User>
{
new User { Id = "U002", Name = "Suzuki" },
new User { Id = "U003", Name = "Tanaka" },
};
C#見た目は同じ U002 ですが、別インスタンスです。
このまま Union すると、「参照が同じかどうか」で比較されるため、両方の U002 が残ってしまいます。
var union = list1.Union(list2).ToList(); // U001, U002(1), U002(2), U003 みたいな状態
C#ここでの重要ポイントは、「クラスの Union はデフォルトでは“参照比較”」だということです。
業務的には「Id が同じなら同じユーザー」とみなしたいので、そのままでは使えません。
プロジェクションしてから Union する
初心者に一番分かりやすいのは、「比較したいキーだけに変換してから和集合を取る」方法です。
var ids1 = list1.Select(x => x.Id);
var ids2 = list2.Select(x => x.Id);
var unionIds = ids1.Union(ids2).ToList(); // U001, U002, U003
C#これで、「どちらかのリストに存在するユーザー Id 一覧」が取れます。
必要なら、そこから元のリストに戻すこともできます。
var unionUsers = list1
.Concat(list2)
.GroupBy(u => u.Id)
.Select(g => g.First())
.ToList();
C#ここでの重要ポイントは、「和集合を取りたいときは、“何をもって同一とみなすか”を先に決める」ことです。
Id なのか、コードなのか、複数項目の組み合わせなのか――それを Select で取り出してから Union する、という流れです。
実務でよくある和集合のパターン
「複数システムのコードを統合して一覧にする」
例えば、A システムと B システムの両方で管理している商品コードを、
「どちらかに存在するものは全部一覧にしたい」というケースです。
var codesA = new[] { "A001", "A002", "A003" };
var codesB = new[] { "A003", "A004", "A005" };
var allCodes = codesA.Union(codesB).ToList(); // A001, A002, A003, A004, A005
C#この allCodes を使って、「どのコードがどのシステムにあるか」を後で調べることもできます。
「権限 A または権限 B を持つユーザーを対象にする」
権限の世界でも、和集合はよく出てきます。
var usersWithRoleA = new[] { "U001", "U002" };
var usersWithRoleB = new[] { "U002", "U003" };
var targetUsers = usersWithRoleA.Union(usersWithRoleB).ToList(); // U001, U002, U003
C#「権限 A か B のどちらかを持っていれば対象」という条件を、
「権限 A ユーザー集合 ∪ 権限 B ユーザー集合」として表現しているイメージです。
和集合を使うときに意識してほしいこと
「重複を残したいのか、1つにまとめたいのか」をはっきりさせる
Union と Concat の違いは、実務でかなり重要です。
重複も含めて「全部のレコード」を見たいなら Concat
同じ値は1回でよく、「種類の一覧」が欲しいなら Union
例えば、「ログを全部時系列で見る」なら Concat でよく、
「登場したユーザー Id の一覧」が欲しいなら Union が向いています。
ここでの重要ポイントは、「和集合は“種類の一覧”を作るイメージ」だということです。
「レコードの一覧」ではなく、「値の集合」を扱っている感覚を持つと、選択を間違えにくくなります。
「何をもって同じとみなすか」を明文化する
オブジェクトの和集合では、必ずこう自分に問いかけてください。
Id が同じなら同じとみなすのか
コードが同じなら同じとみなすのか
コード+日付の組み合わせが同じなら同じとみなすのか
これを日本語で言えるようにしてから、Select や匿名型でキーを作り、Union を呼ぶ。
この順番を守ると、「業務のルールがそのままコードに落ちている」状態になります。
まとめ:「和集合ユーティリティ」は“世界をまとめて、ダブりを整理する道具”
和集合の本質は、
「複数の世界に散らばっている要素を全部集めて、
同じものは1つにまとめた“全体像”を作る」
ことです。
押さえておきたいポイントは、
a.Union(b) は「a と b のどちらかにあるもの全部(重複は1つ)」Concat は「ただくっつけるだけで、重複もそのまま」
オブジェクトでは「何をもって同じとみなすか」を決めてから Select して Union
コード一覧統合、権限の「A または B」、複数システムの統合ビューなどに相性がいい
ここまで腹落ちしていれば、
「とりあえず Concat してから Distinct する」ような雑な書き方から卒業して、
“意図がそのまま読める LINQ ベースの和集合処理”を、落ち着いて書けるようになります。
