読者です 読者をやめる 読者になる 読者になる

かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JS 配列の重複を取り除きたい

配列の重複した値を削除したい時のメモ。

filterでループさせindexOfで値の重複をチェックするパターン

array.indefOf(value)がvalue自身のインデックスと異なる場合は既に配列内に同じ値があるという判定

var arr = [0, 1, 2, 3, 4.1, true, false, 1, "2", "", 4.2, null, undefined, NaN, false];

function removeDuplicateValue(arr) {
  return arr.filter((val, i, self) => {
    return self.indexOf(val) === i;
  });
}

console.log( removeDuplicateValue1(arr) );
// => [ 0, 1, 2, 3, 4.1, true, false, '2', '', 4.2, null, undefined ]

NaNが消えてしまう…

var a = NaN
console.log( a === a ); // false

NaNは自身を含めどの値であってもイコールにならないっぽいので、array.indexOf(NaN) は常に-1となり上記の方法では消えてしまう様です。
NaNを残すようにするには最初に出てきたNaNの時だけfilterのコールバック関数内でtrueを返すようにすればOKでした。(しかしNaN残して使いたい場合ってあるのかな…

var arr = [0, 1, 2, 3, 4.1, true, false, 1, "2", "", 4.2, null, undefined, NaN, false, NaN];

function removeDuplicateValue(arr) {
  let hasNaN = false;
  return arr.filter((val, i, self) => {
    if(isNaN(val) && !hasNaN ) {
      hasNaN = true;
      return true;
    }
    return self.indexOf(val) === i;
  });
}

console.log( removeDuplicateValue(arr) );
// => [ 0, 1, 2, 3, 4.1, true, false, '2', '', 4.2, null, undefined, NaN ]

Set (ES6) を使うパターン

Set
Set オブジェクトにより、primitive valuesでもオブジェクト参照でも、どんな型でも一意の値を格納します。
Set オブジェクトは値のコレクションです。挿入順に要素を反復することができます。Set内の値は 1度だけ発生します。その値はSetコレクション内で一意です。
[出典] Set - JavaScript | MDN

var arr = [0, 1, 2, 3, 4.1, true, false, 1, "2", "", 4.2, null, undefined, NaN, false, NaN];

var a1 = Array.from( new Set(arr) );
console.log(a1);
// => [ 0, 1, 2, 3, 4.1, true, false, '2', '', 4.2, null, undefined, NaN ]

var a2 = [...new Set(arr)];
console.log(a2);
// => [ 0, 1, 2, 3, 4.1, true, false, '2', '', 4.2, null, undefined, NaN ]

Array.from()
Array.from() メソッドは、配列型 (array-like) オブジェクトや反復可能 (iterable) オブジェクトから新しい Array インスタンスを生成します。
[出典] Array.from() - JavaScript | MDN

new Set()で1いの値の反復可能オブジェクトにしてArray.from()に渡して配列化。

スプレッド演算子 ...
スプレッド演算子 は、複数の引数 (関数呼び出しのため) または複数の要素 (配列リテラルのため)、あるいは複数の値 (分割代入のため) が置かれるところで式が展開されます。
[出典] スプレッド演算子 - JavaScript | MDN

配列や反復可能オブジェクトを値で分割展開できる演算子のようです。(スプレッド演算子って名前初めて知りました)
配列の初期化時に反復可能オブジェクトを展開して値として渡して配列化しているようです。
EX

var arr1 = [1,2,3];
var arr2 = [4,5,6];
arr1.push(...arr2); 
arr1; //=> [1, 2, 3, 4, 5, 6];

var set = new Set();
set.add(1);
set.add(2);
set.add(3);
console.log(set); // => Set { 1, 2, 3 }
console.log( [...set] ); // => [ 1, 2, 3 ]

Set()を使えば簡単に重複を削除できるのですが、Array.from...含めてまだサポートしていないブラウザも有るようなのでWEBで本格的に使えるようになるのは使えるようになるのはもう少し先なのかな。と思いました。


[参考]

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問