はじめに
この記事の概要
こんにちは、株式会社TOKOSの杉田です!
今回はJavaScriptのSetクラスの基本的な使い方から、実践的な応用例まで詳しく解説していきます!
あまり使用する頻度はないかもしれませんが重複を許さないユニークな値の集合を扱う場合時などに活躍します!
ぜひ最後まで見ていってみてください!
この記事では、以下の内容について詳しく解説します:
- Setクラスの使用方法
対象読者
- 初学者の方
- フロントエンド開発をされている方
この記事で扱う内容、扱わない内容
この記事で扱う内容 :
- Setクラスの概要
この記事で扱わない内容:
- JavaScriptの基本的な使用方法
概要
JavaScriptのSetクラスは、ES6(ECMAScript 2015)で導入されました!
冒頭でもお伝えしましたが、重複を許さないユニークな値の集合を扱う場合などで使用します!
Setクラスの基礎
Setオブジェクトは、プリミティブ値やオブジェクト参照を含む、どのような型のユニーク(一意)の集合も保持できます。
Setの主な特徴は下記になります。
- 値が一度だけ格納される(重複不可)
- 順序が保持される(挿入順)
- キーを使わず値のみを格納
- NaNとundefinedも格納可能
また、紛らわしいですが配列とは別物になります。
配列との違いは下記になります。
重複要素の扱い
- Set
- 重複する値を保持できない
- 配列
- 同じ値を複数持つことができる
要素の検索効率
- Set
has()
メソッドによる要素検索は非常に高速
- 配列
includes()
やindexOf()
による検索はSetに劣る
要素へのアクセス
- Set
- インデックスによる直接アクセスはできない
- 配列
array[index]
のように直接インデックスでアクセスできる
Setクラスの主要メソッド
Setクラスの主要メソッドは下記になります。
Setのメソッド | 配列での同等の操作 | 説明 |
new Set() | [] | 新しい空のコレクションを作成 |
add(value) | push(value) | 要素を追加する |
delete(value) | splice(array.indexOf(value), 1) | 特定の値を削除する |
has(value) | includes(value) または indexOf(value) !== -1 | 値が存在するか確認する |
clear() | length = 0 または splice(0) | すべての要素を削除する |
forEach(callback) | forEach(callback) | 各要素に対してコールバックを実行 |
values() | values() | 値のイテレータを返す |
entries() | entries() | キーと値のペアのイテレータを返す(配列では[index, value]) |
基本的な使用例
要素の追加・削除などメソッドを使用した例は下記になります。
// 新しいSetを作成
const colors = new Set();
// 要素を追加
colors.add('赤');
colors.add('青');
colors.add('緑');
console.log(colors.size); // 3
// 重複要素の追加は無視される
colors.add('赤');
console.log(colors.size); // 3(変わらない)
// 要素の存在確認
console.log(colors.has('赤')); // true
console.log(colors.has('黄')); // false
// 要素の削除
colors.delete('青');
console.log(colors.size); // 2
// すべての要素を削除
colors.clear();
console.log(colors.size); // 0
上記例のように、重複要素が追加される場合は無視されます!
配列との相互変換
先ほど冒頭で配列とは別物と言いましたが、相互互換ができます!
// 配列からSetへの変換
const array = [1, 2, 2, 3, 4, 4, 5];
const uniqueSet = new Set(array);
console.log(uniqueSet); // Set(5) {1, 2, 3, 4, 5}
// SetからArrayへの変換
const uniqueArray = [...uniqueSet];
console.log(uniqueArray); // [1, 2, 3, 4, 5]
// または Array.from() を使う方法
const anotherUniqueArray = Array.from(uniqueSet);
console.log(anotherUniqueArray); // [1, 2, 3, 4, 5]
実践的な応用例
ここから良く使うパターンを紹介します!
配列から重複を削除する
function removeDuplicates(array) {
return [...new Set(array)];
}
const numbersWithDuplicates = [1, 2, 2, 3, 4, 4, 5, 5, 5];
const uniqueNumbers = removeDuplicates(numbersWithDuplicates);
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]
2つの配列の共通要素を見つける(交差)
function intersection(arrayA, arrayB) {
const setB = new Set(arrayB);
return arrayA.filter(element => setB.has(element));
}
const array1 = [1, 2, 3, 4, 5];
const array2 = [3, 4, 5, 6, 7];
console.log(intersection(array1, array2)); // [3, 4, 5]
2つの配列の差分を見つける(差集合)
function difference(arrayA, arrayB) {
const setB = new Set(arrayB);
return arrayA.filter(element => !setB.has(element));
}
const array1 = [1, 2, 3, 4, 5];
const array2 = [3, 4, 5, 6, 7];
console.log(difference(array1, array2)); // [1, 2]
2つの配列を結合して重複を削除(和集合)
function union(arrayA, arrayB) {
return [...new Set([...arrayA, ...arrayB])];
}
const array1 = [1, 2, 3];
const array2 = [2, 3, 4, 5];
console.log(union(array1, array2)); // [1, 2, 3, 4, 5]
オブジェクト配列から特定のプロパティの重複を削除
function getUniqueByProperty(array, prop) {
const seen = new Set();
return array.filter(item => {
const value = item[prop];
if (seen.has(value)) {
return false;
}
seen.add(value);
return true;
});
}
const users = [
{ id: 1, name: '田中' },
{ id: 2, name: '鈴木' },
{ id: 3, name: '田中' }, // 重複した名前
{ id: 4, name: '佐藤' }
];
const uniqueUsers = getUniqueByProperty(users, 'name');
console.log(uniqueUsers);
// [{ id: 1, name: '田中' }, { id: 2, name: '鈴木' }, { id: 4, name: '佐藤' }]
パフォーマンスの考慮点
Setは配列操作よりも(大量のデータを扱う際は)パフォーマンスが良いです。
大量のデータを扱う場合、配列のincludes()
よりもSetのhas()
の方が高速です。
下記コードは配列と比べた際の結果になります。
結果は100分の1程度になります。
// パフォーマンス比較の例
const largeArray = Array.from({ length: 100000 }, (_, i) => i);
const largeSet = new Set(largeArray);
console.time('Array includes');
const inArray = largeArray.includes(99999);
console.timeEnd('Array includes'); // Array includes: ~5-10ms
console.time('Set has');
const inSet = largeSet.has(99999);
console.timeEnd('Set has'); // Set has: ~0.01-0.05ms
さいごに
今回はあまり馴染み深くないSetクラスについて紹介しました!
配列を使用することが多いとは思いますが、扱うデータによっては簡単に実装できたりパフォーマンスに影響が出るためなるべくSetを使いたいです!