2つのデータセットを比較し、「両方に含まれているデータ」だけを取り出したい場合があります。これを数学的な用語で「積集合(Intersection)」と呼びます。
C#のLINQには、この操作を直感的に行えるIntersectメソッドが用意されています。今回は、採用システムにおける「募集要項の必須スキル」と「応募者の保有スキル」を照合し、合致しているスキルを抽出するシナリオを例に解説します。
Intersectメソッドの概要
Intersectメソッドは、2つのシーケンス(配列やリスト)を比較し、両方のシーケンスに存在する要素のみを含む新しいシーケンスを返します。
主な特徴は以下の通りです。
- 共通項の抽出: 片方のリストにしか存在しない要素は除外されます。
- 結果の一意性: 元のリストに同じ値が複数含まれていても、結果のリストでは重複が削除され、各要素は1回だけ出現します。
実践的なコード例:スキルのマッチング機能
以下のコードは、企業が求めるスキルセットと、応募者が持っているスキルセットを比較し、マッチしたスキルをリストアップする例です。
using System;
using System.Collections.Generic;
using System.Linq;
namespace SkillMatchingSystem
{
class Program
{
static void Main()
{
// シナリオ:
// 採用選考において、募集要項の必須スキルと応募者のスキルを比較する。
// 両方のリストに含まれる「マッチしたスキル」を特定したい。
// 募集要項にある必須スキルリスト
var requiredSkills = new[]
{
"C#",
"SQL Server",
"Azure",
"Docker",
"C#" // リスト作成ミスで重複があってもIntersectが解決します
};
// 応募者の保有スキルリスト
var applicantSkills = new[]
{
"Java",
"C#",
"Python",
"Docker",
"Linux"
};
// 1. Intersectを使用して積集合(共通するスキル)を取得
// requiredSkills と applicantSkills の両方に含まれる文字列のみが抽出されます。
IEnumerable<string> matchedSkills = requiredSkills.Intersect(applicantSkills);
// 結果の出力
Console.WriteLine("--- マッチしたスキル ---");
if (matchedSkills.Any())
{
Console.WriteLine(string.Join(", ", matchedSkills));
}
else
{
Console.WriteLine("マッチするスキルはありませんでした。");
}
}
}
}
実行結果
--- マッチしたスキル ---
C#, Docker
技術的なポイントと注意点
1. 比較の仕組みとカスタム比較
デフォルトでは、要素の型(上記の例ではstring)の既定の比較ロジック(Default等価比較子)が使用されます。文字列の場合、大文字と小文字は区別されます。もし「docker」と「Docker」を同一視してマッチングさせたい場合は、Intersectの第2引数にIEqualityComparer<T>を渡す必要があります。
// 大文字小文字を無視して比較する場合
var matchedSkillsIgnoreCase = requiredSkills.Intersect(
applicantSkills,
StringComparer.OrdinalIgnoreCase
);
2. パフォーマンスと遅延実行
Intersectメソッドは遅延実行(Deferred Execution)されます。実際に比較処理が走るのは、結果をforeachで回したり、ToList()などを呼び出した時点です。内部的にはセットベースのアプローチ(ハッシュセット等)を使用するため、比較的大きなコレクション同士の比較でも効率的に動作します。
3. 重複の排除
入力元のリスト(例:requiredSkills)に重複データが含まれていたとしても、Intersectの結果は数学的な集合の定義に従い、重複のない一意なリストとなります。このため、事前のDistinct呼び出しは不要です。
まとめ
Intersectメソッドを使用することで、ループ処理や条件分岐を複雑に組み合わせることなく、シンプルに「共通項」を抽出できます。データ照合やフィルタリング機能の実装において、可読性を高めるために非常に有効な手段です。
