JavaScriptで独自のSetクラスを実装する方法【和集合・差集合の実装例つき】
セット(Set)は、重複しない値のコレクションを扱うための基本的なデータ構造です。JavaScriptには標準で組み込みのSetオブジェクトが用意されていますが、その内部動作を理解するには、独自のMySetクラスをゼロから実装してみるのが効果的です。
以下は、基本操作(追加・削除・検索・クリア)、反復処理、そして和集合と差集合を求める静的メソッドまでを含んだ、MySetクラスの完全な実装例です。
MySetクラスの実装例
class MySet {
constructor() {
this.container = {};
}
display() {
console.log(this.container);
}
has(val) {
return Object.prototype.hasOwnProperty.call(this.container, val);
}
add(val) {
if (!this.has(val)) {
this.container[val] = val;
return true;
}
return false;
}
delete(val) {
if (this.has(val)) {
delete this.container[val];
return true;
}
return false;
}
clear() {
this.container = {};
}
forEach(callback) {
for (let prop in this.container) {
callback(prop);
}
}
static union(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) {
console.log("The given objects are not of type MySet");
return null;
}
let newSet = new MySet();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.add(elem));
return newSet;
}
static difference(s1, s2) {
if (!(s1 instanceof MySet) || !(s2 instanceof MySet)) {
console.log("The given objects are not of type MySet");
return null;
}
let newSet = new MySet();
s1.forEach(elem => newSet.add(elem));
s2.forEach(elem => newSet.delete(elem));
return newSet;
}
}
各メソッドの役割
基本操作
- has(val):指定した値がセットに存在するかどうかを判定します。プロトタイプチェーン上のプロパティを誤って参照しないよう、
Object.prototype.hasOwnProperty.call()を使用しています。 - add(val):値がまだ存在しない場合のみ追加し、成功すれば
true、すでに存在する場合はfalseを返します。これにより重複が自動的に排除されます。 - delete(val):値が存在すれば削除して
true、存在しなければfalseを返します。 - clear():セットの内容をすべて破棄し、空の状態に戻します。
- display():デバッグ用に、内部コンテナの中身をコンソールへ出力します。
反復処理
- forEach(callback):内部の各要素に対してコールバック関数を実行します。後述する和集合・差集合の処理でも活用されています。
集合演算(静的メソッド)
- union(s1, s2):2つのセットの和集合を返します。引数が
MySet型であるかを検証し、型が一致しない場合は警告を出力してnullを返します。 - difference(s1, s2):最初のセットから2番目のセットに含まれる要素を取り除いた差集合を返します。
使用例
const setA = new MySet();
setA.add(1);
setA.add(2);
setA.add(3);
const setB = new MySet();
setB.add(2);
setB.add(4);
// 存在チェック
console.log(setA.has(2)); // true
console.log(setA.has(9)); // false
// 要素の削除
setA.delete(1);
setA.display(); // { '2': 2, '3': 3 }
// 和集合
const unionResult = MySet.union(setA, setB);
unionResult.display(); // { '2': 2, '3': 3, '4': 4 }
// 差集合
const diffResult = MySet.difference(setA, setB);
diffResult.display(); // { '3': 3 }
実装時の注意点
- 内部ではプレーンなオブジェクトをコンテナとして使っているため、数値などのキーは文字列に変換されて格納されます。
- 型チェックの際、
!s1 instanceof MySetのように書くと!が先に評価され、意図どおりに動作しません。必ず!(s1 instanceof MySet)のように括弧で囲みましょう。 - 実際の開発では、ES2015(ES6)以降に組み込まれている標準の
Setオブジェクトを使うのが一般的です。MySetのような自作実装は、セットというデータ構造の仕組みを学ぶのに最適な教材となります。
-
JavaScriptにおける配列とSetの違いとは?重複値の扱いと要素アクセスをわかりやすく解説
JavaScriptのSet(セット)オブジェクトは、ES2015(ES6)で新たに導入されたデータ型です。従来から広く使われている配列(Array)と比べると、いくつか重要な違いがあります。 配列とSetの主な違い 重複した値の扱い: 配列は同じ値をいくつでも格納できますが、Setでは同一の値は1つしか保持されません。重複した値は自動的に除外されるのが大きな特徴です。 要素へのアクセス方法: 配列ではインデックス(例:arr[0])を使って任意の位置の要素へ直接アクセスできます。一方、Setにはインデックスの概念がなく、要素は挿入された順序どおりに先頭から順番に辿ることしかできません。
-
JavaScriptでinnerHTMLを設定する方法をわかりやすく解説
JavaScriptでHTML要素の内容を動的に書き換えたい場合に便利なのが、innerHTMLプロパティです。innerHTMLを使えば、指定した要素の中にHTML文字列をそのまま挿入・置き換えることができます。本記事では、innerHTMLを設定する正しい構文と、実際に動作するサンプルコードを初心者向けに解説します。 innerHTMLを設定する正しい構文 innerHTMLを設定する際の正しい構文は以下のとおりです。 document.getElementById(yourIdName).innerHTML=yourValue; この構文では、まずgetElementById()メソッド