JavaScriptにおいて、セットとは、一意のプリミティブやオブジェクトの参照だけを格納できる、配列に似たデータ構造です。
セットは、セットのコンストラクターを使って作成する必要があります。コンストラクターに配列を渡すと、値を入れた状態で初期化できます。
const emptySet = new Set();
const setWithInitialValues = new Set(['hello', 'world']);
値は、セットの要素のいずれかと厳密に等しい場合、そのセットに追加することはできません。
const set = new Set();
set.add(10);
set.add(10); // 10 is strictly equal to 10, so it can't be added again
set.size;
//=> 1;
set.has(10);
//=> true
set.delete(10);
//=> true; 10 was removed
set.delete(10);
//=> false; 10 is not in the set, so nothing happened
const obj = { color: 'magenta' };
const eerilySimilarObj = { color: 'magenta' };
set.add(obj);
set.add(eerilySimilarObj); // obj and eerilySimilarObj reference different objects, so they can both be added
set.size;
//=> 2
set.clear();
set.size;
//=> 0
配列は、セットのコンストラクターを使ってセットに変換します。セットは、スプレッド構文かArray.from()を使って配列に変換できます。
const arrayWithDuplicates = [7, 3, 3, 9, 3];
const arrayWithoutDuplicates = [...new Set(arrayWithDuplicates)]; // [7, 3, 9]
const anotherArrayWithoutDuplicates = Array.from(new Set(arrayWithDuplicates)); // [7, 3, 9]
セットはキー付きコレクションです。つまり、要素はキーでインデックス付けされ、挿入順に繰り返し処理できます。セットの要素では_キー_と_値_が同じなので、Set.keys()とSet.values()は同じように使えます。
const apples = ['Granny Smith', 'Honey Crisp', 'Royal Gala'];
const appleSet = new Set(apples);
for (let apple of appleSet.keys()) {
console.log(apple);
}
// 'Granny Smith'
// 'Honey Crisp'
// 'Royal Gala'
for (let apple of appleSet.values()) {
console.log(apple);
}
// 'Granny Smith'
// 'Honey Crisp'
// 'Royal Gala'
for (let apple of appleSet.entries()) {
console.log(apple);
}
// ['Granny Smith', 'Granny Smith']
// ['Honey Crisp', 'Honey Crisp']
// ['Royal Gala', 'Royal Gala']
データの集まりを保存するのに(配列ではなく)セットが選ばれるのは、たいてい、保存する値を一意にする必要があるからです。しかし、配列でも一意性を保つことは可能なので、なぜそうなるのかはすぐにはわからないかもしれません。
簡単に言うと、セットは検索に最適化されていて、配列はそうではないからです。配列の検索メソッド(Array.indexOf()など)の実行時間は、配列のサイズに比例して長くなります。つまり、配列に含まれる要素が多いほど、検索にかかる時間も長くなります。一方、セットの検索メソッドの実行時間は一定で、セットのサイズに関係なく変わりません。
ただし実際には、コレクションに膨大な量のデータが含まれていない限り、この性能差は無視できる程度です。