Array内の重複を除く方法
今回は先週reduce()について調べた時に気になった、「Array内の重複を除く方法」について。
色々な手法がありそうなのでまとめていく。
JavaScriptでArray内の重複を除く方法
その1: reduceを使用する方法
その2: filterとindexOfを使用する方法
その3: Setを使用する方法(オススメ!)
reduceを使用する方法:
先週見た通り、reduce()メソッドを使用すれば、重複を削除しながら新しい配列を構築することが可能。
・・・もう少し手軽な方法を探そう。
const array = ["P", "P", "l", "a", "l", "t", "t", "y", "t", "p", "u", "s"];
const arrayWithNoDuplicates = array.reduce(
(acc, currentV) => {
if (!acc.includes(currentV)) {
return [...acc, currentV];
}
return acc;
},
[],
);
console.log(arrayWithNoDuplicates);
// Output: ['P', 'l', 'a', 't', 'y', 'p', 'u', 's']
filterとindexOfを使用する方法:
この方法では、各要素が元の配列内で最初に現れるインデックスを持つ場合にのみ、それを残すように新しい配列を作成する。
const array = ["P", "P", "l", "a", "l", "t", "t", "y", "t", "p", "u", "s"];
const arrayWithNoDuplicates = array.filter((letter, index, self) => self.indexOf(letter) === index);
console.log(arrayWithNoDuplicates);
// Output: ['P', 'l', 'a', 't', 'y', 'p', 'u', 's']
filterメソッドの引数が3つも入っていて動揺したが、以下はMDNより一部引用。
// アロー関数
filter((element) => { /* … */ } )
filter((element, index) => { /* … */ } )
filter((element, index, array) => { /* … */ } )
element
: 配列内で処理中の現在の要素index
: 配列内で処理中の現在の要素の位置array :
filter()
が呼び出された配列
self.indexOf(letter) === index の部分がtrueのものだけで新しいArrayを作るのがfilterメソッドだが、このindexOfメソッドを覚えているだろうか。
.indexOf(): 「具体的な値など」がArrayの中に含まれていれば最初に見つかったのがArrayの何番目にあるかIndexを返す。一つもなければ「−1」が返る。※同じ値が2つ以上含まれているArrayの場合は1つ目の場所しか返ってこない。
- 最初の”P”は、
self.indexOf("P")
は0で、index
も0。したがって、条件は0 === 0
でtrue
となる - 2番目の”P”は、s
elf.indexOf("P")
は0だが、index
は1。条件は0 === 1
でfalse
となる。
最初に現れた要素のインデックスと現在のインデックスを比較し、一致する場合は true
を返すことにより、重複を取り除く方法だが・・・もっとすんなり入ってくるものは無いのか?
Setを使用する方法:
メモ:
引用元:MDNSet
とArray.from()
に対応している環境を使っている場合は、const arrayWithNoDuplicates = Array.from(new Set(myArray))
を使うことで重複要素を除去された配列を取得することができます。
先週から気になっていたこれ!(MDNを読み進めていくと、Array .fromはスプレッド構文に置き換えられていたので以下はスプレッド構文で書いていくことにする)
まずは重複削除のコードを見てほしい。
const array = ["P", "P", "l", "a", "l", "t", "t", "y", "t", "p", "u", "s"];
const arrayWithNoDuplicates = [...new Set(array)];
console.log(arrayWithNoDuplicates);
// Output: ['P', 'l', 'a', 't', 'y', 'p', 'u', 's']
えっ!?だいぶスッキリ!
っていうかスッキリし過ぎていて何が起こっているのかよく分からない(私と同じ)人は
一緒に […new Set(array)] について紐解きながら見ていこう。
Setについて
まずはSet()について。これはSetオブジェクトというどんな型でも(つまり文字列でも、数字でも、Arrayでもオブジェクトでも)入れられる特別なオブジェクト。Setオブジェクトは個人的にはこれまでほとんど使ったことなかったが、普通のオブジェクトとの違いで、一番の特徴は、このオブジェクトには重複した値を入れられないということ。
① “new”をつけるとSetオブジェクトが新規作成される。
Setの後の括弧()に何も入れない場合は空っぽのSetオブジェクトが作成されるが、
② ()の中にArrayを渡すと中身が一つずつオブジェクトに渡される。
③ Setオブジェクトに値を追加したいときは.addを使うが、すでにSetオブジェクト内に同じ値が存在するときは無視される。これを利用して、重複を自動的に削除することができると言うわけ。
const set1 = new Set(); // ①空っぽのSetオブジェクトが作成される
const set2 = new Set([1, 2, 3, 4, 5]);
// ② ()の中にArrayを渡すと中身が一つずつオブジェクトに渡される
console.log(set1); // Output : {}
console.log(set2); // Output : {1, 2, 3, 4, 5}
set2.add(6);// ③ set2に6を追加する
set2.add(5);// 5は重複しているため無視される
console.log(set2); // Output : {1, 2, 3, 4, 5, 6}
※ちなみに②で[1, 2, 3, 4, 5]と言うArrayを分解せずにそのままオブジェクトに入れたい場合は[]をさらに追加してnew Set([[1, 2, 3, 4, 5]])とすれば入れられるが、ArrayやオブジェクトはShallowコピーになるので、new Set([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]])とした場合、重複とは見做されないので注意!!
[…]について
今回はnew Set(array)としていたので、arrayの中の各文字がSetオブジェクトに一つずつ重複無い状態で入れられた。でもこれをオブジェクトではなくArrayの形に戻したい。そのために④[]で囲って、スプレッド構文 “…”でobjectWithNoDuplicatesの中身をArrayに移していく。
const array = ["P", "P", "l", "a", "l", "t", "t", "y", "t", "p", "u", "s"];
const objectWithNoDuplicates = new Set(array);
console.log(objectWithNoDuplicates);
//Output: {'P', 'l', 'a', 't', 'y', 'p', 'u', 's'}
const arrayWithNoDuplicates = [...objectWithNoDuplicates] // ④ 空っぽのArrayを作成
console.log(arrayWithNoDuplicates);
// Output: ['P', 'l', 'a', 't', 'y', 'p', 'u', 's']
2ステップに分けたけど、これを一度にやったのが […new Set(array)]。
const array = ["P", "P", "l", "a", "l", "t", "t", "y", "t", "p", "u", "s"];
const arrayWithNoDuplicates = [...new Set(array)];
console.log(arrayWithNoDuplicates);
// Output: ['P', 'l', 'a', 't', 'y', 'p', 'u', 's']
いや〜お見事!
この間、日本各地でクラゲが大量発生していて、漁業などに影響出ているというニュースを見た。
クラゲといえば毒。刺された人とかの話を聞くと怖くて海に入れないけど、
カモノハシもオスにだけ毒がある!後ろ足のかかとの部分にある爪を敵に刺して毒を注入!?
人が刺されても死には至らないけど相当痛いらしい。(Photo taken at Taronga Zoo)
