重複の削除と検出/SetとMap
配列やリストから重複要素を削除する方法や検出などのSetとMapの活用例
重複の削除とは
配列やリストから重複している要素を削除し一意な要素のみを残す処理はプログラミングでよく遭遇する課題です。データの正規化や集計処理の前処理などで頻繁に使用されます。
TypeScriptではSetオブジェクトやループ処理など、複数の方法で重複を削除できます。ここではそれぞれの方法の特徴と使い分けについて解説します。
Setを使った重複削除
最もシンプルで効率的な方法はSetオブジェクトを使う方法です。Setは重複を許さないコレクションであり、自動的に重複要素を除外してくれます。
Setによる重複削除
配列をSetに変換しスプレッド構文で再度配列に戻すことで簡潔に実装できます。
Setは内部的にハッシュテーブルを使用しているため、O(n)の時間計算量で重複削除が可能です。つまり要素数に比例した実行時間で処理が行われます。これは効率的で、後で効率の悪い方法も紹介します。
文字列の重複削除
文字列から重複する文字を削除する場合も同様にSetを使用できます。文字列を配列に分割し、Setで重複を削除してから再度結合します。
文字列の重複文字削除
文字列に対してSetを直接適用すると自動的に文字列が文字の配列として扱われます。スプレッド構文で展開しjoinで結合することで重複のない文字列を得られます。
ちなみに文字列が文字の配列として扱われるという挙動はここでは便利ですが、場合によっては扱っているデータが配列なのか文字列なのか勘違いしやすいので注意が必要です。
より複雑な条件の重複削除
Setは単純な重複削除には適しています。しかし、実務ではより複雑な条件で重複を判定したい場合もあると思います。その場合にはMapオブジェクトの使用が有効です。Mapオブジェクトキーに重複判定の基準となるプロパティを設定し、値にオブジェクト全体を格納することで、重複削除が可能になります。
オブジェクトの重複削除
Mapオブジェクトはキーと値のペアを作成し、同じキーの要素は後から追加されたもので上書きされます。最後にvalues()で値のみを取り出して配列に変換しています。
filterを使った重複削除
ここで古い方法を紹介しますが、配列のfilterメソッドとindexOfを組み合わせることでも重複削除が可能です。この方法は、各要素が最初に出現する位置と現在のインデックスが一致するかを確認します。
filterによる重複削除
この方法は実装は単純ですが、filterとindexOfで二度も配列全体を探索するためO(n²)の時間計算量になります。実際にはSetオブジェクトを使った方法(O(n))を推奨します。もしもこのようなコードを見つけたら、上で紹介したようなSetを使う方法にリファクタリングすることを意識しましょう。
重複数のカウント
重複を削除するだけでなく、各要素の出現回数を知りたい場合などの複雑な処理にもMapを利用することができます。このようにMapは応用の効くオブジェクトのため、使い方を覚えておくと便利です。
重複のカウント
まとめ
TypeScriptで重複を削除する方法について解説しました。基本的にはSetを使った方法が最もシンプルで効率的です。オブジェクトの配列やより複雑な条件での重複削除には、Mapを使った方法が適しています。
また、重複の削除だけでなく出現回数のカウントなど様々な用途にMapを使うことができます。配列を扱う問題に直面した時にはMapの利用を検討することをお勧めします。