JavaScriptで配列の重複を削除する方法|Set活用
配列に同じ値が混ざっていて、1つずつに絞りたい場面、JavaScriptならSetオブジェクトを使うと、重複を許さないリストを数行で作れます。
Setは「集合」を扱うオブジェクトです。集合とは、同じ値を2つ以上持たない値の集まりのことで、同じ値を何度追加しても1つしか残りません。配列のように[0]と書いて番号で要素を取り出すことはできません。
重複が問題になる場面
重複した値は、集計や表示のズレにつながります。たとえば次のような場面です。
- 同じユーザーIDが二重に数えられる集計処理
- 同じタグが複数回登録されてしまうタグ入力
- 同じ値が混ざった状態で返ってくる外部APIのレスポンス
この記事では、Setを使う方法と、Setを使わず配列だけで実現する方法を紹介します。
Setで重複を許さないリストを作る
new Set()で空のSetを作り、add()で値を追加します。すでにある値を追加してもエラーにならず、そのまま無視されます。
// Setを使って重複を許さないリストを作成
const uniqueList = new Set();
// 値を追加
uniqueList.add(1);
uniqueList.add(2);
uniqueList.add(2); // これは無視される
uniqueList.add(3);
console.log(uniqueList); // Set(3) { 1, 2, 3 }
// 上記でログに内容が出力されない場合
console.log([...uniqueList]); // Array [1, 2, 3]
// 配列に変換する場合
const arrayList = Array.from(uniqueList);
console.log(arrayList); // [1, 2, 3]
console.logにSetをそのまま渡すと、環境によっては中身が表示されないことがあります。その場合は、スプレッド構文(...)で配列に展開して表示します。Array.from()でも配列に変換できます。配列に変換すれば、mapやfilterなどの配列メソッドをそのまま使えます。
すでに手元にある配列から重複を取り除きたいだけなら、その配列をnew Set()に渡して、結果をArray.from()で配列に戻す流れで済みます。
値の有無を確認する
Setに値が入っているかはhas()で確認します。戻り値はtrueかfalseです。
// Setを使って重複を許さないリストを作成
const uniqueList = new Set();
// 値を追加
uniqueList.add(1);
uniqueList.add(2);
uniqueList.add(3);
console.log(uniqueList.has(1)); // true
console.log(uniqueList.has(0)); // false
配列だけで重複を排除する
Setを使わなくても、filterメソッドとindexOfメソッドを組み合わせれば、手動で重複を排除できます。以下はその例です。
const originalList = [1, 2, 2, 3, 4, 4, 5];
// 重複を排除する関数
const uniqueList = originalList.filter((value, index, self) => {
return self.indexOf(value) === index;
});
console.log(uniqueList); // [1, 2, 3, 4, 5]
仕組みは次のとおりです。
indexOf: 値が最初に見つかった位置を返すメソッド- 位置の比較: 現在の位置と最初の位置が一致すれば、初登場の値
filter: 条件に合う要素だけを残すメソッド
2つ目の2は、最初に見つかった位置(1)と現在の位置(2)が違うため除外されます。includesメソッドで、結果用の配列にすでに入っているかを確認しながら追加する書き方もあります。
Setと配列の方法はどちらを使うか
基本はSetです。違いは次のとおりです。
Set: 記述が短く、データが多くても高速filterとindexOf: 要素ごとに先頭から探し直すため、データが増えるほど速度が低下
重複排除でハマりやすい点
オブジェクトは中身ではなく参照(メモリ上の場所)で比較されます。{ id: 1 }を2回追加すると、中身が同じでも別物として両方残ります。オブジェクトの配列から重複を取り除くときは、IDなど判定に使う値だけをSetに入れて確認します。
NaN(数値ではない値)も注意が必要です。SetはNaN同士を同じ値として扱いますが、indexOfはNaNを見つけられません。filterとindexOfの方法では、NaNが結果から消えます。
まとめ
- 重複を許さないリストは
Setで作成 - 値の有無は
has()で確認 - 配列だけで行う場合は、
filterメソッドとindexOfメソッドの組み合わせ - 迷ったら
Setを選択
