なぜこの記事を書こうと思ったのか
配列内部での重複を確認して、抽出したいというケースがあったのですが、実装方法がわからなかったため、インプットアウトプットを行いたく、記事を書きました。
簡単なboolean判定から
//重複しているものが存在している配列
const hasSameValueArray: string[] = ["A", "B", "C", "D", "E", "A"];
//重複しているものが存在している配列
const notHasSameValueArray: string[] = ["A", "B", "C", "D", "E"];
//重複が存在する場合はtrue, 重複が存在しない場合はfalseを返す関数
const isDuplicated = <T,>(elements: T[]): boolean => {
const elementsToSetObject = new Set(elements);
return !(elementsToSetObject.size === elements.length);
};
console.log(isDuplicated(hasSameValueArray)); // true
console.log(isDuplicated(notHasSameValueArray)); //false
解説
含まれている、含まれていないという点だけを検証する関数を用意してみました。
配列を引数にnew Setに引数として引き渡すと、「重複を許さないコレクション」として、setコレクションが生成されます。
先ほどの関数に重複する内容を持つ配列を引き渡し、関数の内部で,console出力を追加してみます。
//重複しているものが存在している配列
const hasSameValueArray: string[] = ["A", "B", "C", "D", "E", "A"];
//重複が存在する場合はtrue, 重複が存在しない場合はfalseを返す関数
const isDuplicated = <T,>(elements: T[]): boolean => {
const elementsToSetObject = new Set(elements);
//追加したconsole.log
console.log(elementsToSetObject);
// 結果 -> Set(5) {'A', 'B', 'C', 'D', 'E'}
return !(elementsToSetObject.size === elements.length);
};
console.log(isDuplicated(hasSameValueArray)); // true
重複していた「A」が1個になっていますね。
あとは実際の引数は配列のためarray.length値で検証。Setオブジェクトに対しては専用のSet.sizeで内部の件数が返却されるため数値の不一致を検証してvalue値としてBooleanを返却するといった具合です。
内部で使用されているSetオブジェクトの解説については以下の記事がとてもわかりやすかったのでご紹介します。
重複しているものを抽出したいケース
先ほどは、setを使用した簡単なboolean判定となっていたため、比較的コードは簡潔なものが用意出来たかなと思いますが.... タイトルの通りで「重複しているものを抽出したいケース」では、どうしたらいいのでしょうか?
//重複しているものが存在している配列
const hasSameValueArray: string[] = ["A", "B", "C", "D", "E", "A", "B"];
// -> ここから、「"A", "B"」だけを抽出したケース
実際に書いてみた
//重複しているものが存在している配列
const hasSameValueArray: string[] = ["A","B","C","D","E","A","A","B", "B", "B"];
/***配列内部で重複している値を取り出す関数 */
const extractDuplicated = <T,>(array: T[]) => {
const extractSame = array.filter(
(item) => !(array.indexOf(item) === array.lastIndexOf(item))
);
return Array.from(new Set(extractSame));
};
console.log(extractDuplicated(hasSameValueArray));
// 結果 -> ['A', 'B']
解説
複数の重複があっても問題ないのか?と疑問だったため今回は同一の値を適当に複数入れてみました。
array.indexOfとarray.lastIndexOfを使用して、該当のものが最初と、最後に表示されるindex番号を取得。
重複検証を実施して「最初と最後のindex番号が一致しないもの」を抽出しています。
fileterで抽出しただけでは結果として
["A","B","A","A","B","B","B"]
が返却されてしまうため、これを先ほどのSetコレクション化。重複を削除した後にArray.fromメソッドで配列化する。この結果
console.log(extractDuplicated(hasSameValueArray));
// 結果 -> ['A', 'B']
となり必要だった「重複している値の抽出」が完了しました。
filter使って判定するっていう考え方があんまり思いつかなかったのですが、
以下の記事を参照にして作ってみました。
最後に
本質的に自分の解決したかった課題は2個目の「抽出する側」だったのですが、
1個目のBoolean判定を返す関数を書いてるうちに、ん?と答えが浮かんできた次第でした。
自分の言葉でのアウトプットの重要性がわかったので今後も継続していきたいと思います。