Set とは何か(まずイメージから)
Set は、ES6 で追加された
「重複を許さない値の集まり(コレクション)」 です。
- 配列:同じ値を何回入れてもいい
- Set:同じ値は 1 回しか入らない
というイメージを持つと分かりやすいです。
const s = new Set();
s.add(1);
s.add(2);
s.add(2); // 同じ値は無視される
console.log(s); // Set(2) { 1, 2 }
console.log(s.size); // 2
JavaScriptここが重要です。
「同じものが入っても困る」「重複を自動で取り除きたい」 ときに、Set が本領を発揮します。
配列で「重複チェック」「重複削除」をゴリゴリ書くより、Set を使う方が圧倒的に素直です。
Set の基本操作(add / has / delete / clear)
Set の作り方と add での追加
const visited = new Set();
visited.add("東京");
visited.add("大阪");
visited.add("東京"); // 2回目は無視される
console.log(visited); // Set(2) { '東京', '大阪' }
console.log(visited.size); // 2
JavaScriptadd(value) で値を追加します。
同じ値を何度 add しても、Set の中には 1 個しか入りません。
has で存在チェック、delete で削除
console.log(visited.has("東京")); // true
console.log(visited.has("名古屋")); // false
visited.delete("大阪");
console.log(visited.has("大阪")); // false
JavaScripthas(value) で「その値が入っているか」をチェックできます。delete(value) は指定した要素を削除します。
全削除したいときは clear() を使います。
visited.clear();
console.log(visited.size); // 0
JavaScriptsize で要素数がすぐ分かる
const s = new Set();
s.add(1);
s.add(2);
console.log(s.size); // 2
JavaScript配列の length と同じイメージで、Set は size で長さを取得します。
重複しないとはどういうことか(ここを深掘り)
原始値(数値・文字列など)の場合
const s = new Set();
s.add(1);
s.add(1);
s.add("1");
s.add("1");
console.log(s); // Set(2) { 1, '1' }
JavaScript1(数値)と "1"(文字列)は別物なので、両方入ります。
しかし、1 を何回 add しても、Set の中には 1つだけです。
オブジェクトや配列は「同一参照かどうか」で判断される
const s = new Set();
const a = { id: 1 };
const b = { id: 1 }; // 中身は同じでも別オブジェクト
s.add(a);
s.add(b);
console.log(s.size); // 2
JavaScriptオブジェクトや配列の場合、
「中身が同じかどうか」ではなく、「同じもの(同じ参照)かどうか」で重複が判断されます。
const s = new Set();
const arr = [1, 2];
s.add(arr);
s.add(arr); // 同じ参照を2回 add
console.log(s.size); // 1
JavaScriptここが重要です。
Set は「=== で同じと判断されるかどうか」で重複を判定する。
原始値なら「値そのもの」、オブジェクトなら「同じもの(参照)」かどうかで決まります。
Set のイテレーション(for…of / forEach)
Set は for…of でそのまま回せる
const s = new Set(["東京", "大阪", "名古屋"]);
for (const city of s) {
console.log(city);
}
// 東京
// 大阪
// 名古屋
JavaScriptSet は「挿入した順」で値を返してくれます。
forEach も使える
s.forEach((value) => {
console.log("value:", value);
});
JavaScriptMap の forEach と違い、Set のコールバックは (value, value, set) という少し変わった引数構成ですが、
普通は value だけ見ておけば十分です。
s.forEach((value, sameValue, set) => {
// sameValue は value と同じ
});
JavaScriptよくある用途と具体例
例1:配列から重複を取り除く(ユニークな要素だけ)
一番よく使うパターンです。
const nums = [1, 2, 2, 3, 3, 3, 4];
const unique = [...new Set(nums)];
console.log(unique); // [1, 2, 3, 4]
JavaScriptnew Set(nums) で「重複を取り除いた Set」を作り、[...] で配列に戻しています。
例2:すでに見たことがあるかどうかを高速にチェック
例えば、ログイン試行時に「すでに試したメールアドレスかどうか」をチェックするイメージ。
const triedEmails = new Set();
function tryLogin(email) {
if (triedEmails.has(email)) {
console.log("このメールアドレスはすでに試しました");
return;
}
triedEmails.add(email);
console.log("ログイン試行:", email);
// 実際のログイン処理…
}
tryLogin("a@example.com");
tryLogin("b@example.com");
tryLogin("a@example.com");
// ログイン試行: a@example.com
// ログイン試行: b@example.com
// このメールアドレスはすでに試しました
JavaScript配列で同じことをしようとすると、includes で毎回探したり、重複したら push しないようにしたりと、コードがもっさりします。
Set は「重複を気にせず add して OK」というのがかなり楽です。
例3:2つの配列の共通要素(積集合)を求める
数学の集合のイメージです。
const a = [1, 2, 3, 4];
const b = [3, 4, 5, 6];
const setB = new Set(b);
const intersection = a.filter((x) => setB.has(x));
console.log(intersection); // [3, 4]
JavaScriptsetB.has(x) が高速に判定できるので、
共通部分の計算も効率よく書けます。
例4:2つの配列を合わせてユニークな集合にする(和集合)
const a = [1, 2, 3];
const b = [3, 4, 5];
const union = [...new Set([...a, ...b])];
console.log(union); // [1, 2, 3, 4, 5]
JavaScriptSet と配列をどう使い分けるか
配列が向いている場面
配列は
- 順番に意味がある(1番目、2番目…)
- 重複を許容したい
- インデックスでアクセスしたい(
arr[0]など)
といったケースに向いています。
例えば、「ユーザーがクリックした履歴」などは配列が自然です。
const clicks = [];
clicks.push("top");
clicks.push("about");
clicks.push("top"); // top を複数回クリックしてもよい
JavaScriptSet が向いている場面
Set は
- 値の重複を許したくない
- 「この値が存在するかどうか」を高速に判定したい
- 順序は必要だけど、インデックスでアクセスする必要はあまりない
といったケースに向いています。
例えば、「今ログインしているユーザーIDの集合」など。
const loggedInUserIds = new Set();
loggedInUserIds.add(1);
loggedInUserIds.add(2);
loggedInUserIds.add(1); // 重複しても 1 は 1 つだけ
console.log(loggedInUserIds.has(1)); // true
JavaScriptここが重要です。
「順序付きのリスト + 重複OK」なら配列。
「順序付きの集合 + 重複NG」なら Set。
このイメージを持っておくと、自然に使い分けられます。
Set と Map / オブジェクトの関係
Set は「値だけ」、Map は「キーと値」
- Set:値だけを持つ(各値は一意)
- Map:キーと値のペアを持つ
const set = new Set(["A", "B", "C"]); // 値だけ
const map = new Map([
["A", 1],
["B", 2],
]); // キーと値
JavaScript「何かの“存在”だけ管理したい」なら Set、
「キーに紐づく値を持ちたい」なら Map を選びます。
オブジェクトは「固定フィールド」、Set/Map は「可変な集合」
- オブジェクト:あらかじめ決まった「項目」を持つデータ(id, name, age …)
- Set/Map:増えたり減ったりする「集合」を扱うコレクション
この違いを意識すると、
「ここはオブジェクト」「ここは Set/Map」と切り分けやすくなります。
まとめ
Set の核心は、
「重複しない値の集合を、簡単かつ効率よく扱うためのデータ構造」 であることです。
押さえておきたいポイントは次の通りです。
add,has,delete,clear,sizeが基本操作- 同じ値を何度
addしても 1 回分しか入らない(重複が自動的に排除される) - オブジェクトや配列も要素として持てる(=== で同じかどうかで判定)
for...ofやforEachで順序通りにループできる- 「配列の重複を消す」「共通部分(積集合)や和集合を計算する」「存在チェック」などで特に威力を発揮する
- 「重複OKのリスト」なら配列、「重複NGの集合」なら Set を選ぶとよい
まずは、配列で書いているコードの中から
- 重複を消したい場面
includesで存在チェックしている場面
を一つ見つけて、それを Set に置き換えてみてください。
Set を一度「重複削除の必殺技」として体感すると、どこで使えば気持ちいいかがどんどん見えてきます。
