かもメモ

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

JS 2つの配列の差分を取得したい

  1. 値の差分をチェック
  2. 値とインデックスでチェック

1. 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[8, 2, 8, 4, 7, 9, 11, 8, 10]

2. 
[0, 1, 2, 3, 4, 5, 6]
['', 1, NaN, "3", null, 5, undefined]

3. 
[]
["いちご", "あおい", "らん"]

4. 
[1, "サーバル", 3, "かばん"]
[1, 7, "ボス"]

5. 
["あぶくま", "きそ", "しまかぜ", "ひびき", "わかば", "ながなみ"]
["あぶくま", "きそ", "しまかぜ", "ひびき", "ながなみ"]

1. 2つの配列の値の差分を新しい配列にして返す

いずれかの配列にしか値が存在しない場合を返せばいいので、indexOfで配列内に値が存在するかをチェックして判定。

function getArrayDiff(arr1, arr2) {
  let arr = arr1.concat(arr2);
  return arr.filter((v, i)=> {
    return !(arr1.indexOf(v) !== -1 && arr2.indexOf(v) !== -1);
  });
}

👇 出力結果

1.  
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[8, 2, 8, 4, 7, 9, 11, 8, 10]
// =>  [ 1, 3, 5, 6, 11 ]
2.
[0, 1, 2, 3, 4, 5, 6]
['', 1, NaN, "3", null, 5, undefined]
// => [ 0, 2, 3, 4, 6, '', NaN, '3', null, undefined ]
3. 
[]
["いちご", "あおい", "らん"]
// => [ 'いちご', 'あおい', 'らん' ]
4.
[1, "サーバル", 3, "かばん"]
[1, 7, "ボス"]
// => [ 'サーバル', 3, 'かばん', 7, 'ボス' ]
5.
["あぶくま", "きそ", "しまかぜ", "ひびき", "わかば", "ながなみ"]
["あぶくま", "きそ", "しまかぜ", "ひびき", "ながなみ"]
// => [ 'あぶくま', 'きそ', 'しまかぜ', 'ひびき', 'わかば', 'ながなみ' ]

Array.prototype.includes() - JavaScript | MDN
配列に値があるかBoolean値で返すarray.includes()という関数もあるっぽいけど、ECMAScript 2017 Draft (ECMA-262)って書いてあるからES7なのかな?
 

2. 2つの配列の値の差分をインデックス含めてチェックして返す

2-1. 新旧の比較のように、配列Aと配列Bを比べ配列Aから変化しているものを返す

function getArrayIndexValueDiff(oldArr, newArr) {
  return newArr.filter((v, i)=> oldArr[i] !== v);
}

👇 出力結果

1.  
old: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
new: [8, 2, 8, 4, 7, 9, 11, 8, 10]
// =>  [ 8, 8, 7, 9, 11, 10 ]
2.
old: [0, 1, 2, 3, 4, 5, 6]
new: ['', 1, NaN, "3", null, 5, undefined]
// => [ '', NaN, '3', null, undefined ]
3. 
old: []
new: ["いちご", "あおい", "らん"]
// => [ 'いちご', 'あおい', 'らん' ]
4.
old: [1, "サーバル", 3, "かばん"]
new: [1, 7, "ボス"]
// => [ 7, 'ボス' ]
5.
old: ["あぶくま", "きそ", "しまかぜ", "ひびき", "わかば", "ながなみ"]
new: ["あぶくま", "きそ", "しまかぜ", "ひびき", "ながなみ"]
// => [ 'ながなみ' ]

2-2. お互いの配列で異なっているものを返す

function getArrayIndexValueDiffBoth(arr1, arr2) {
  let _a1 = arr1,
      _a2 = arr2,
      _a2Len,
      res = [[], []],
      reverse = false;

  // ループのベースは要素が多い方の配列にする
  if(_a1.length < _a2.length) {
    _a1 = arr2;
    _a2 = arr1;
    reverse = true;
  }
  _a2Len = _a2.length;

  res[0] = _a1.filter((v, i)=> {
    if(_a2[i] !== v) {
      // 元の配列に存在していない値(undefined)は除外
      if( i < _a2Len) {
        res[1].push( _a2[i] );
      }
      return true;
    }
  });

  if(reverse) {
    res.reverse();
  }
  return res;
}

もう少しエレガントな書き方がありそうな気がする…
👇 出力結果

1. 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[8, 2, 8, 4, 7, 9, 11, 8, 10]
// => [ [ 1, 3, 5, 6, 7, 9, 10 ], [ 8, 8, 7, 9, 11, 10 ] ]
2. 
[0, 1, 2, 3, 4, 5, 6]
['', 1, NaN, "3", null, 5, undefined]
// =>[ [ 0, 2, 3, 4, 6 ], [ '', NaN, '3', null, undefined ] ]
3. 
[]
["いちご", "あおい", "らん"]
// => [ [], [ 'いちご', 'あおい', 'らん' ] ]
4. 
[1, "サーバル", 3, "かばん"]
[1, 7, "ボス"]
// => [ [ 'サーバル', 3, 'かばん' ], [ 7, 'ボス' ] ]
5. 
["あぶくま", "きそ", "しまかぜ", "ひびき", "わかば", "ながなみ"]
["あぶくま", "きそ", "しまかぜ", "ひびき", "ながなみ"]
// => [ [ 'わかば', 'ながなみ' ], [ 'ながなみ' ] ]

 
アロー関数で書いている部分は別にアロー関数でなくても大丈夫なはずです。
差分ってえっちなコトバな印象になってしまったのはきっとインターネッツのせい。


プログラマのための論理パズル 難題を突破する論理思考トレーニング

プログラマのための論理パズル 難題を突破する論理思考トレーニング