はじめに
個人で開発しているブログサイトのとある機能にて、JavaScriptで重複を含む複数の数値が格納された配列から、重複を削除する方法が知りたかったので、調べてみたところ、すぐに2つの実装方法が見つかりました。今回は、そちらの方法の紹介に加えて、2つの方法の相違点から、実装にあたって考慮するべき点についてまとめてみました。
結論
先にこの記事での結論をお伝えすると、**JavaScriptで重複を削除する際には、基本的にSetオブジェクトを使うことをお勧めします。**下で紹介するようなindexOfメソッドとfilterメソッドを用いた方法もありますが、処理の対象となるデータが将来的に大きくなることが予想される場合、計算量の大幅な増大につながるため、処理速度の問題となる可能性があります。下記で実装方法を含めて説明します。
1. indexOfとfilterメソッドを使った場合
JavaScriptでの重複を削除方法について調べると、こちらの方法が最も紹介されています。配列の各要素のインデックスが、配列内で最初に一致するかどうかを条件としてfilterメソッドでフィルタリングすることで、配列から重複を取り除くことができます。
const arrayA = [1, 2, 3, 3, 1, 4];
const arrayB = arrayA.filter((element, index) => {
return arrayA.indexOf(element) == index;
})
console.log(arrayB); //[ 1, 2, 3, 4 ]
2. new Set()を用いた場合
2つ目の方法として、EcmaScript 2015からJavaScriptに標準で導入されたSetオブジェクトを用いるやり方があります。
MDNのリファレンスによると、Setオブジェクトについて以下のように説明されています。
Set オブジェクトは、プリミティブ値やオブジェクト参照を問わず、あらゆる型で一意の値を格納できます。
つまり、文字列や数値などのデータ型に関係なく、配列内を必ず一意な要素のみに変換してくれるというものです。下記は、1つ目の方法と同じ数値の配列における重複の削除を行っています。
const arrayA = [1, 2, 3, 3, 1, 4];
const arrayB = Array.from(new Set(arrayA));
console.log(arrayB); //[ 1, 2, 3, 4 ]
上の実装の2行目は、以下のようにスプレッド構文を用いて記述することも可能です。
const arrayB = [...new Set(arrayA)];
また、重複削除後の配列内の各要素の順序は、元配列の要素の順序であることが保証されています。
2つの方法において異なる点
この2つの実装方法で得られる結果は同じですが、計算量と処理速度に大きな違いがあります。
こちらの記事で詳細に書かれていますが、indexOfとfilterメソッドの場合、配列の要素数の2乗に比例した計算量が発生します。例えば、データ量が100倍になれば、計算量は10000倍になるということに。。また、要素数が100000個の場合の2つの方法の処理速度は、およそ55倍違うそうです(Setオブジェクトの方が速い)。このようなスケーラビリティ上の問題点の有無がindexOfとfilterメソッドと、Setオブジェクトの大きな相違点になります。
また、コードの簡潔さの面から見ても、Setオブジェクトが優れていることが上の実装例から分かります。
感想
今回は、JavaScriptで配列内の重複を削除する方法についてまとめてみました。
この方法について調べる前は、コード量についてはある程度意識して、プログラムを実装していました。しかし、処理の計算量については、ほとんど考慮できていませんでした。システムの規模が大きくなったり、処理の対象となるデータが将来的に肥大化していく可能性がある場合は、エラーなく動くだけでなく、計算量を意識したプログラムの実装が求められることを、この比較を通して感じました。
アルゴリズム大事。。勉強します。。