web-dev-qa-db-ja.com

Javascriptで2つの配列の違いを知るにはどうすればいいですか?

JavaScriptで2つの配列の違いを返す方法はありますか?

例えば:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

// need ["c", "d"]

アドバイスは大歓迎です。

575
John Adawan

通常の配列と比較していると思います。そうでない場合は、forループをfor .. in _ループに変更する必要があります。

function arr_diff (a1, a2) {

    var a = [], diff = [];

    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (var k in a) {
        diff.Push(k);
    }

    return diff;
}

console.log(arr_diff(['a', 'b'], ['a', 'b', 'c', 'd']));
console.log(arr_diff("abcd", "abcde"));
console.log(arr_diff("zxc", "zxc"));

下位互換性を気にしないのであれば、より良い解決策はfilterを使うことです。それでも、この解決策は機能します。

174
Thinker
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

[1,2,3,4,5,6].diff( [3,4,5] );  
// => [1, 2, 6]

["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
// => ["test5", "test6"]
Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

var dif1 = [1,2,3,4,5,6].diff( [3,4,5] );  
console.log(dif1); // => [1, 2, 6]


var dif2 = ["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
console.log(dif2); // => ["test5", "test6"]

indexOfとfilterはie9以前では使用できません。

839
Joshaven Potter

ES7を使うより良い方法があります。

交差点

 let intersection = arr1.filter(x => arr2.includes(x));

Intersection difference Venn Diagram

[1,2,3] [2,3]の場合は[2,3]になります。一方、[1,2,3] [2,3,5]は同じことを返します。

違い

let difference = arr1.filter(x => !arr2.includes(x));

Right difference Venn Diagram

[1,2,3] [2,3]の場合は[1]になります。一方、[1,2,3] [2,3,5]は同じことを返します。

対称差 の場合、次のことができます。

let difference = arr1
                 .filter(x => !arr2.includes(x))
                 .concat(arr2.filter(x => !arr1.includes(x)));

Symmetric difference Venn Diagram

このようにして、arr2に含まれていないarr1のすべての要素を含む配列を取得します。その逆も同様です。

@Joshaven Potterが彼の答えを指摘したように、これをArray.prototypeに追加して、次のように使用することができます。

Array.prototype.diff = arr1.filter(x => arr2.includes(x));
[1, 2, 3].diff([2, 3])
728
Luis Sieira

これは、jQueryを使って、探している結果を正確に得る最も簡単な方法です。

var diff = $(old_array).not(new_array).get();

diffold_arrayにはないがnew_arrayにあったものを含みます

300
superphonic

アンダースコアの差分法 (またはそのドロップイン置換、 Lo-Dash )でもこれを実行できます。

(R)eturns the values from array that are not present in the other arrays

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

他のアンダースコア関数と同様に、よりオブジェクト指向のスタイルで使用することもできます。

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);
148
mahemoff

普通のJavaScript

「違い」には2つの解釈が考えられます。私はあなたが欲しいものをあなたに選ばせます。たとえば、

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. ['a']を取得したい場合は、この関数を使用してください。

    function difference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.Push(a1[i]);
        }
      }
      return result;
    }
    
  2. ['a', 'c']どちらか __s___ a1またはa2に含まれるすべての要素 - ただし両方ではない - いわゆる対称差)を取得したい場合は、次の関数を使用します。

    function symmetricDifference(a1, a2) {
      var result = [];
      for (var i = 0; i < a1.length; i++) {
        if (a2.indexOf(a1[i]) === -1) {
          result.Push(a1[i]);
        }
      }
      for (i = 0; i < a2.length; i++) {
        if (a1.indexOf(a2[i]) === -1) {
          result.Push(a2[i]);
        }
      }
      return result;
    }
    

ロダッシュ/アンダースコア

Lodashを使用している場合は、 _.difference(a1, a2) (上記のケース1)または _.xor(a1, a2) (ケース2)を使用できます。

Underscore.jsを使用している場合は、ケース1の場合に _.difference(a1, a2) 関数を使用できます。

ES6セット、大規模アレイ用

上記のコードはすべてのブラウザで機能します。ただし、約10,000個を超えるアイテムの大規模配列では、O(n²)の複雑さがあるため、処理が非常に遅くなります。最近の多くのブラウザでは、スピードを上げるためにES6 Set オブジェクトを利用することができます。 Lodashは利用可能なときに自動的にSetを使用します。 lodashを使用していない場合は、 Axel Rauschmayerのブログ投稿 にヒントを得た次の実装を使用してください。

function difference(a1, a2) {
  var a2Set = new Set(a2);
  return a1.filter(function(x) { return !a2Set.has(x); });
}

function symmetricDifference(a1, a2) {
  return difference(a1, a2).concat(difference(a2, a1));
}

ノート

-0、+ 0、NaN または疎な配列を気にしている場合、すべての例の動作は驚くべきことであるか、または明白ではないかもしれません。 (ほとんどの場合、これは関係ありません。)

63
Jo Liss

この場合は Set を使用できます。それはこの種の操作(和集合、交差点、差)に最適化されています。

それがあなたのケースにあてはまるのを確かめてください、それが重複を許さないならば。

var a = new JS.Set([1,2,3,4,5,6,7,8,9]);
var b = new JS.Set([2,4,6,8]);

a.difference(b)
// -> Set{1,3,5,7,9}
35
Samuel Carrijo

対称差 を得るには、両方の方法で(あるいは複数の配列の場合はすべての方法で)配列を比較する必要があります

enter image description here


ES7(ECMAScript 2016)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => !b.includes(x)),
        ...b.filter(x => !a.includes(x))
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => !unique.includes(x));
    }));
}

ES6(ECMAScript 2015)

// diff between just two arrays:
function arrayDiff(a, b) {
    return [
        ...a.filter(x => b.indexOf(x) === -1),
        ...b.filter(x => a.indexOf(x) === -1)
    ];
}

// diff between multiple arrays:
function arrayDiff(...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter(x => unique.indexOf(x) === -1);
    }));
}

ES5(ECMAScript 5.1)

// diff between just two arrays:
function arrayDiff(a, b) {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var other = i === 1 ? a : b;
        arr.forEach(function(x) {
            if (other.indexOf(x) === -1) {
                diff.Push(x);
            }
        });
    })

    return diff;
}

// diff between multiple arrays:
function arrayDiff() {
    var arrays = Array.prototype.slice.call(arguments);
    var diff = [];

    arrays.forEach(function(arr, i) {
        var others = arrays.slice(0);
        others.splice(i, 1);
        var otherValues = Array.prototype.concat.apply([], others);
        var unique = otherValues.filter(function (x, j) { 
            return otherValues.indexOf(x) === j; 
        });
        diff = diff.concat(arr.filter(x => unique.indexOf(x) === -1));
    });
    return diff;
}

例:

// diff between two arrays:
const a = ['a', 'd', 'e'];
const b = ['a', 'b', 'c', 'd'];
arrayDiff(a, b); // (3) ["e", "b", "c"]

// diff between multiple arrays
const a = ['b', 'c', 'd', 'e', 'g'];
const b = ['a', 'b'];
const c = ['a', 'e', 'f'];
arrayDiff(a, b, c); // (4) ["c", "d", "g", "f"]

オブジェクトの配列の違い

function arrayDiffByKey(key, ...arrays) {
    return [].concat(...arrays.map( (arr, i) => {
        const others = arrays.slice(0);
        others.splice(i, 1);
        const unique = [...new Set([].concat(...others))];
        return arr.filter( x =>
            !unique.some(y => x[key] === y[key])
        );
    }));
}

例:

const a = [{k:1}, {k:2}, {k:3}];
const b = [{k:1}, {k:4}, {k:5}, {k:6}];
const c = [{k:3}, {k:5}, {k:7}];
arrayDiffByKey('k', a, b, c); // (4) [{k:2}, {k:4}, {k:6}, {k:7}]
30
Luca Borrione
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

両方の配列をマージすると、一意の値が一度だけ表示されるため、indexOf()はlastIndexOf()と同じになります。

28
pdbrito

ある配列を別の配列から減算するには、単に以下のスニペットを使用してください。

var a1 = ['1','2','3','4','6'];
var a2 = ['3','4','5'];

var items = new Array();

items = jQuery.grep(a1,function (item) {
    return jQuery.inArray(item, a2) < 0;
});

2番目には存在しない最初の配列の項目である['1、' 2 '、' 6 ']を返します。

したがって、問題のサンプルによると、次のコードが正確な解決策です。

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var _array = new Array();

_array = jQuery.grep(array2, function (item) {
     return jQuery.inArray(item, array1) < 0;
});
17
Al___

indexOf()を使った解決策は小さな配列には大丈夫でしょうが、それらが長くなるにつれてアルゴリズムの性能はO(n^2)に近づきます。これは、配列のエントリをキーとして格納するための連想配列としてオブジェクトを使用することによって、非常に大きな配列に対してより優れたパフォーマンスを発揮するソリューションです。また、重複するエントリを自動的に排除しますが、文字列値(または文字列として安全に格納できる値)でのみ機能します。

function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.Push(k); } }
  for (k in o2) { if (!(k in o1)) { diff.Push(k); } }
  return diff;
}

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
arrayDiff(a1, a2); // => ['c', 'd']
arrayDiff(a2, a1); // => ['c', 'd']
12
maerics

ES2015による機能的アプローチ

2つの配列間でdifferenceを計算することはSet操作の1つです。この用語は、検索速度を上げるために、ネイティブのSet型を使用する必要があることをすでに示しています。とにかく、2セット間の差を計算するとき、3つの置換があります。

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]

これはこれらの順列を反映する機能的な解決策です。

difference

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( differencel(xs) (ys) );

正しいdifference

differencerは簡単です。引数が反転されたdifferencelです。あなたは便利のために関数を書くことができます:const differencer = flip(differencel)。それで全部です!

対称difference

左右が決まったので、対称型のdifferenceを実装するのも簡単です。

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const concat = y => xs => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// left difference

const differencel = xs => ys => {
  const zs = createSet(ys);
  return filter(x => zs.has(x)
     ? false
     : true
  ) (xs);
};


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,3,6,7,8,9];


// run the computation

console.log( difference(xs) (ys) );

この例は、関数型プログラミングが何を意味するのかという印象を得るための良い出発点であると思います。

さまざまな方法で接続できるビルディングブロックを使用したプログラミング。

11
user6445533

セットとスプラット演算子を使ったES6の登場(Firefoxでのみ動作していた時点で、 互換性表 をチェックしてください)では、以下のライナーを書くことができます。

var a = ['a', 'b', 'c', 'd'];
var b = ['a', 'b'];
var b1 = new Set(b);
var difference = [...new Set([...a].filter(x => !b1.has(x)))];

これは[ "c", "d" ]になります。

11
Salvador Dali

Joshaven Potterによる上記の答えは素晴らしいです。ただし、配列Cにない配列Bの要素を返しますが、逆の要素は返しません。たとえば、var a=[1,2,3,4,5,6].diff( [3,4,5,7]);の場合は、==> [1,2,6]を出力しますが、not[1,2,6,7]、 2つの間の実際の差です。上記のPotterのコードを引き続き使用できますが、比較を一度だけ逆にやり直すこともできます。

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return !(a.indexOf(i) > -1);});
};

////////////////////  
// Examples  
////////////////////

var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
var b=[3,4,5,7].diff([1,2,3,4,5,6]);
var c=a.concat(b);
console.log(c);

これは出力するはずです:[ 1, 2, 6, 7 ]

10
user1685068

問題を解決するための別の方法

function diffArray(arr1, arr2) {
    return arr1.concat(arr2).filter(function (val) {
        if (!(arr1.includes(val) && arr2.includes(val)))
            return val;
    });
}

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]
8
Iurii Golskyi
Array.prototype.difference = function(e) {
    return this.filter(function(i) {return e.indexOf(i) < 0;});
};

eg:- 

[1,2,3,4,5,6,7].difference( [3,4,5] );  
 => [1, 2, 6 , 7]
7
riyas tk

これはどう:

Array.prototype.contains = function(needle){
  for (var i=0; i<this.length; i++)
    if (this[i] == needle) return true;

  return false;
} 

Array.prototype.diff = function(compare) {
    return this.filter(function(elem) {return !compare.contains(elem);})
}

var a = new Array(1,4,7, 9);
var b = new Array(4, 8, 7);
alert(a.diff(b));

だからこのようにあなたはそれらの違いを得るためにarray1.diff(array2)をすることができます(しかしアルゴリズムのための恐ろしい時間複雑さ - O(array1.length x array2.length)私は信じています)

6
Cat

JavaScriptのフィルタ機能を使用した非常にシンプルなソリューション:

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr = arr1.concat(arr2);
  
    newArr = myArr.filter(function(item){
      return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
    });
   alert(newArr);
}

diffArray(a1, a2);
6
Yash Thakkar

http://phrogz.net/JS/ArraySetMath.jsを使用して あなたはできる:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var array3 = array2.subtract( array1 );
// ["test5", "test6"]

var array4 = array1.exclusion( array2 );
// ["test5", "test6"]
4
Phrogz
  • 純粋なJavaScriptソリューション(ライブラリなし)
  • 古いブラウザと互換性があります(filterは使用しません)
  • O(n^2)
  • 配列項目の比較方法を指定できるオプションのfnコールバックパラメータ
function diff(a, b, fn){
    var max = Math.max(a.length, b.length);
        d = [];
    fn = typeof fn === 'function' ? fn : false
    for(var i=0; i < max; i++){
        var ac = i < a.length ? a[i] : undefined
            bc = i < b.length ? b[i] : undefined;
        for(var k=0; k < max; k++){
            ac = ac === undefined || (k < b.length && (fn ? fn(ac, b[k]) : ac == b[k])) ? undefined : ac;
            bc = bc === undefined || (k < a.length && (fn ? fn(bc, a[k]) : bc == a[k])) ? undefined : bc;
            if(ac == undefined && bc == undefined) break;
        }
        ac !== undefined && d.Push(ac);
        bc !== undefined && d.Push(bc);
    }
    return d;
}

alert(
    "Test 1: " + 
    diff(
        [1, 2, 3, 4],
        [1, 4, 5, 6, 7]
      ).join(', ') +
    "\nTest 2: " +
    diff(
        [{id:'a',toString:function(){return this.id}},{id:'b',toString:function(){return this.id}},{id:'c',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        [{id:'a',toString:function(){return this.id}},{id:'e',toString:function(){return this.id}},{id:'f',toString:function(){return this.id}},{id:'d',toString:function(){return this.id}}],
        function(a, b){ return a.id == b.id; }
    ).join(', ')
);
3
Trevor

これはうまくいっています:基本的に2つの配列をマージし、重複を探し、重複していないものを新しい配列にプッシュするのが違いです。

function diff(arr1, arr2) {
  var newArr = [];
  var arr = arr1.concat(arr2);
  
  for (var i in arr){
    var f = arr[i];
    var t = 0;
    for (j=0; j<arr.length; j++){
      if(arr[j] === f){
        t++; 
        }
    }
    if (t === 1){
      newArr.Push(f);
        }
  } 
  return newArr;
}
3
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

これは私のための作品です

3
Stan D

ちょっと考えてみてください…挑戦のために;-)これでうまくいくでしょう…(文字列、数字などの基本的な配列のために)入れ子になった配列なし

function diffArrays(arr1, arr2, returnUnion){
  var ret = [];
  var test = {};
  var bigArray, smallArray, key;
  if(arr1.length >= arr2.length){
    bigArray = arr1;
    smallArray = arr2;
  } else {
    bigArray = arr2;
    smallArray = arr1;
  }
  for(var i=0;i<bigArray.length;i++){
    key = bigArray[i];
    test[key] = true;
  }
  if(!returnUnion){
    //diffing
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = null;
      }
    }
  } else {
    //union
    for(var i=0;i<smallArray.length;i++){
      key = smallArray[i];
      if(!test[key]){
        test[key] = true;
      }
    }
  }
  for(var i in test){
    ret.Push(i);
  }
  return ret;
}

array1 = "test1", "test2","test3", "test4", "test7"
array2 = "test1", "test2","test3","test4", "test5", "test6"
diffArray = diffArrays(array1, array2);
//returns ["test5","test6","test7"]

diffArray = diffArrays(array1, array2, true);
//returns ["test1", "test2","test3","test4", "test5", "test6","test7"]

ソートは上記のようには行われない可能性がありますが、必要に応じて、配列に対して.sort()を呼び出してソートします。

2
scunliffe

ベストアンサーのためのちょっとした修正

function arr_diff(a1, a2)
{
  var a=[], diff=[];
  for(var i=0;i<a1.length;i++)
    a[a1[i]]=a1[i];
  for(var i=0;i<a2.length;i++)
    if(a[a2[i]]) delete a[a2[i]];
    else a[a2[i]]=a2[i];
  for(var k in a)
   diff.Push(a[k]);
  return diff;
}

これは現在のタイプの要素を考慮に入れるでしょう。 b/c a [a1 [i]]にすると、値をその元の値から文字列に変換するので、実際の値は失われます。

2
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
var diff = [];
for (var i in a2) {
   var found = false;
   for (var j in a1) {
      if (a2[i] === a1[j]) found = true;
   }
   if (found === false) diff.Push(a2[i]);
}

それは簡単です。オブジェクトと一緒に使用して、オブジェクトの1つのプロパティをチェックすることもできます。好きです、

if (a2[i].id === a1[j].id) found = true;

// es6アプローチ

function diff(a, b) {
  var u = a.slice(); //dup the array
  b.map(e => {
    if (u.indexOf(e) > -1) delete u[u.indexOf(e)]
    else u.Push(e)   //add non existing item to temp array
  })
  return u.filter((x) => {return (x != null)}) //flatten result
}
2
copremesis

あなたはunderscore.jsを使用することができます: http://underscorejs.org/#intersection

配列にはメソッドが必要です。

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
2
Sebastien

これは、Thinkerによって受け入れられた回答に触発されましたが、Thinkerの回答は配列が集合であると仮定しているようです。配列が[ "1", "2" ][ "1", "1", "2", "2" ]であるならば、それはバラバラになります

これらの配列の違いは[ "1", "2" ]です。次の解決策はO(n * n)なので理想的ではありませんが、大きな配列がある場合は、Thinkerの解決策よりもメモリの点で有利です。

そもそもセットを扱っているのであれば、Thinkerの解決策は間違いなく優れています。フィルタにアクセスできる新しいバージョンのJavascriptがある場合は、それも使用する必要があります。これは、セットを扱っておらず、古いバージョンのJavaScriptを使用している人のためのものです(何らかの理由で)。

if (!Array.prototype.diff) { 
    Array.prototype.diff = function (array) {
        // if the other array is a falsy value, return a copy of this array
        if ((!array) || (!Array.prototype.isPrototypeOf(array))) { 
            return this.slice(0);
        }

        var diff = [];
        var original = this.slice(0);

        for(var i=0; i < array.length; ++i) {
            var index = original.indexOf(array[i]);
            if (index > -1) { 
                original.splice(index, 1);
            } else { 
                diff.Push(array[i]);
            }
        }

        for (var i=0; i < original.length; ++i) {
            diff.Push(original[i]);
        }
        return diff;
    }
}   
2
redusek

配列が単純型ではない場合は、上記の答えのいずれかを適用できます。

Array.prototype.diff = function(a) {
        return this.filter(function(i) {return a.map(function(e) { return JSON.stringify(e); }).indexOf(JSON.stringify(i)) < 0;});
    };

このメソッドは複雑なオブジェクトの配列に対して機能します。

2
Vadim
function diff(arr1, arr2) {
  var filteredArr1 = arr1.filter(function(ele) {
    return arr2.indexOf(ele) == -1;
  });

  var filteredArr2 = arr2.filter(function(ele) {
    return arr1.indexOf(ele) == -1;
  });
  return filteredArr1.concat(filteredArr2);
}

diff([1, "calf", 3, "piglet"], [1, "calf", 3, 4]); // Log ["piglet",4]
2
huy-tran

対称 および 線形複雑度 。 ES6が必要です。

function arrDiff(arr1, arr2) {
    var arrays = [arr1, arr2].sort((a, b) => a.length - b.length);
    var smallSet = new Set(arrays[0]);

    return arrays[1].filter(x => !smallSet.has(x));
}
1
Dodgie

ある配列を別の配列から減算したい人への対応として...

1000以上の要素がこれを試して言うと言わないならば...

新しい変数を設定してArray01を複製し、Array03という名前を付けます。

それでは、バブルソートアルゴリズムを使用して、Array01の要素とArray02の要素を比較し、一致するものが見つかったら、次のようにArray03を実行します。

 if (Array01[x]==Array02[y]) {Array03.splice(x,1);}

NB:バブルソートのネストしたループを壊さないように、Array01ではなくArray03を修正しています。

最後に、簡単な割り当てでArray03の内容をArray01にコピーすれば完了です。

1
MPS

CoffeeScriptのバージョン

diff = (val for val in array1 when val not in array2)
1
m.e.conroy

まだ別の答えですが、いくつかのアルゴリズムと技術サポートを比較するjsperfに言及している人はいないようです: https://jsperf.com/array-difference-javascript フィルタを使用すると、最良の結果が得られます。ありがとう

1
cancerbero

私は、古い配列と新しい配列を取り入れ、追加された項目の配列と削除された項目の配列を与えてくれる類似の関数が欲しかったし、それが効率的であることを望みました。

あなたがここに私の提案した解決策で遊ぶことができます: http://jsbin.com/osewu3/12

誰かがそのアルゴリズムに対する何か問題/改善を見ることができますか?ありがとうございます。

コードリスト:

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // Push to diff?
          r.Push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // Push to diff?
          a.Push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}
1
Ian Grainger

単にすべての値を比較し、繰り返さない値を持つ配列を返します。

var main = [9, '$', 'x', 'r', 3, 'A', '#', 0, 1];

var arr0 = ['Z', 9, 'e', '$', 'r'];
var arr1 = ['x', 'r', 3, 'A', '#'];
var arr2 = ['m', '#', 'a', 0, 'r'];
var arr3 = ['$', 1, 'n', '!', 'A'];


Array.prototype.diff = function(arrays) {
    var items = [].concat.apply(this, arguments);
    var diff = [].slice.call(items), i, l, x, pos;

    // go through all items
    for (x = 0, i = 0, l = items.length; i < l; x = 0, i++) {
        // find all positions
        while ((pos = diff.indexOf(items[i])) > -1) {
            // remove item + increase found count
            diff.splice(pos, 1) && x++;
        }
        // if item was found just once, put it back
        if (x === 1) diff.Push(items[i]);
    }
    // get all not duplicated items
    return diff;
};

main.diff(arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"

[].diff(main, arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"
1
MarekZeman91

私は、異なるライブラリを使わないで簡単な答えを探していました、そして、私はここで言及されていないと私は思いつきました。私はそれがどれほど効率的であるか、あるいは何でもうまくいくかわからない。

    function find_diff(arr1, arr2) {
      diff = [];
      joined = arr1.concat(arr2);
      for( i = 0; i <= joined.length; i++ ) {
        current = joined[i];
        if( joined.indexOf(current) == joined.lastIndexOf(current) ) {
          diff.Push(current);
        }
      }
      return diff;
    }

私のコードでも私は複製を取り出す必要がありますが、私はそれが常に好まれるとは限らないと思います。

主な欠点は、すでに却下されている多くの選択肢を比較している可能性があることです。

1
Samuel

HasOwnPropertyを使用しない場合は、不適切な要素があります。例えば:

[1,2,3].diff([1,2]); //Return ["3", "remove", "diff"] This is the wrong version

私のバージョン:

Array.prototype.diff = function(array2)
  {
    var a = [],
        diff = [],
        array1 = this || [];

    for (var i = 0; i < array1.length; i++) {
      a[array1[i]] = true;
    }
    for (var i = 0; i < array2.length; i++) {
      if (a[array2[i]]) {
        delete a[array2[i]];
      } else {
        a[array2[i]] = true;
      }
    }

    for (var k in a) {
      if (!a.hasOwnProperty(k)){
        continue;
      }
      diff.Push(k);
    }

    return diff;
  }

Ian Graingerのソリューションに似ています(ただし、TypeScriptで)。

function findDiffs(arrayOne: string[], arrayTwo: string[]) {

    let onlyInArrayOne = []
    let onlyInArrayTwo = []
    let share = []
    let [arrayOneCopy, arrayTwoCopy] = [[...arrayOne], [...arrayTwo]]

    arrayOneCopy.sort(); arrayTwoCopy.sort()

    while (arrayOneCopy.length !== 0 && arrayTwoCopy.length !== 0) {
        if (arrayOneCopy[0] == arrayTwoCopy[0]) {
            share.Push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
            arrayTwoCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] < arrayTwoCopy[0]) {
            onlyInArrayOne.Push(arrayOneCopy[0])
            arrayOneCopy.splice(0, 1)
        }
        if (arrayOneCopy[0] > arrayTwoCopy[0]) {
            onlyInArrayTwo.Push(arrayTwoCopy[0])
            arrayTwoCopy.splice(0, 1)
        }
    }
    onlyInArrayTwo = onlyInArrayTwo.concat(arrayTwoCopy)
    onlyInArrayOne = onlyInArrayOne.concat(arrayOneCopy)

    return {
        onlyInArrayOne,
        onlyInArrayTwo,
        share,
        diff: onlyInArrayOne.concat(onlyInArrayTwo)
    }
}

// arrayOne: [ 'a', 'b', 'c', 'm', 'y' ] 
// arrayTwo: [ 'c', 'b', 'f', 'h' ]
//
// Results: 
// { 
//    onlyInArrayOne: [ 'a', 'm', 'y' ],
//    onlyInArrayTwo: [ 'f', 'h' ],
//    share: [ 'b', 'c' ],
//    diff: [ 'a', 'm', 'y', 'f', 'h' ] 
// }
1

私が現在使用しているjQueryソリューションに貢献します。

if (!Array.prototype.diff) {
    Array.prototype.diff = function (a) {
        return $.grep(this, function (i) { return $.inArray(i, a) === -1; });
    }; 
}
1
Johan

Samuel:「私のコードでも複製を取り出す必要がありますが、これは必ずしも推奨されているわけではないと思います。主な欠点は、既に拒否されている多くのオプションを比較することです。」

2つのリスト、配列などを比較するとき、要素が1000未満の場合、3GLの世界の業界標準は重複を避けるバブルソートを使用することです。

コードは次のようになります。(テストされていませんが、動作するはずです)

var Array01=new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P');
var Array02=new Array('X','B','F','W','Z','X','J','P','P','O','E','N','Q');
var Array03=Array01;

for(x=1; x<Array02.length; x++) {
 for(y=0; y<Array01.length-1; y++) {
  if (Array01[y]==Array02[x]) {Array03.splice(y,1);}}}

Array01=Array03;

出力をテストするには.

for(y=0; y<Array01.length; y++) {document.write(Array01[y])}
1
MPS

難しいやり方 (.indexOfよりも凝ったことをしたい場合)

var difference = function (source, target) {
    return source.reduce(function (diff, current) { 
        if (target.indexOf(current) === -1) { 
            diff.Push(current); 
        }

        return diff; 
    }, []);
}

簡単な方法

var difference = function (source, target) {
    return source.filter(function (current) {
        return target.indexOf(current) === -1;
    });
}
0
Santhos

これは私が2つの配列の違いを得るために使う関数です - 数値、文字列、混合num /文字列配列に適しています。配列/多次元配列内のオブジェクトリテラルではない

function diff(arr1, arr2) {

    var x, 
        t;

    function uniq(a, b) {
        t = b;

        if( (b === 0 && x[b+1]!==a) || 
           (t > 0 && a !== x[b+1] && a !== x[b-1]) ) {
            return  a;
        }
    }


    x = arr1.concat(arr2).sort();

    return x.filter(uniq);
}

var a1 = ['a', 'b', 'e', 'c'],
    a2 = ['b', 'a', 'c', 'f' ];

diff(a1, a2);
0
jfab fab

配列にオブジェクトが含まれている場合は、属性を比較したい場合、もう少し難しくなります。

幸いなことにlodash_contains_.pluckを使ってこれをとても簡単にします:

var list1 = [{id: 1},{id: 2}];
var list1 = [{id: 1},{id: 2}, {id: 3}];

//es6
var results = list2.filter(item => {
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//es5
var results = list2.filter(function(item){
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//results contains [{id: 3}]
0
chovy

迅速な解決策他の人がすでに同じ方法の異なるバリエーションを投稿しているようですが。これが巨大な配列に最適かどうかはわかりませんが、私の配列では10または15より大きくならないでしょう。

違い b - a

for(var i = 0; i < b.length; i++){
  for(var j = 0; j < a.length; j ++){
    var loc = b.indexOf(a[j]);
    if(loc > -1){
      b.splice(loc, 1);
    }
  }
}
0
Ajoy

この質問は古いですが、それでも javascript配列の減算のためのトップヒットです それで私は私が使っているソリューションを追加したいと思いました。これは次のような場合に適しています。

var a1 = [1,2,2,3]
var a2 = [1,2]
//result = [2,3]

次の方法で目的の結果が得られます。

function arrayDifference(minuend, subtrahend) {
  for (var i = 0; i < minuend.length; i++) {
    var j = subtrahend.indexOf(minuend[i])
    if (j != -1) {
      minuend.splice(i, 1);
      subtrahend.splice(j, 1);
    }
  }
  return minuend;
}

この関数には、被減数に存在しない減数からの値は含まれません。

var a1 = [1,2,3]
var a2 = [2,3,4]
//result = [1]
0
cazzer

元の配列を気にせず、編集するのに問題がない場合、これはより速いアルゴリズムです:

let iterator = arrayA.values()
let result = []
for (entryA of iterator) {
    if (!arrayB.includes(entryA)) {
        result.Push(entryA)
    } else {
        arrayB.splice(arrayB.indexOf(entryA), 1) 
    }
}

result.Push(...arrayB)
return result

0
Rohanil
var result = [];
var arr1 = [1,2,3,4];
var arr2 = [2,3];
arr1.forEach(function(el, idx) {
    function unEqual(element, index, array) {
        var a = el;
        return (element!=a);
    }
    if (arr2.every(unEqual)) {
        result.Push(el);
    };
});
alert(result);
0
fog
const difference = function (baseArray, arrayToCampare, callback = (a, b) => a!== b) {
  if (!(arrayToCampare instanceof Array)) {
    return baseArray;
  }
  return baseArray.filter(baseEl =>
    arrayToCampare.every(compareEl => callback(baseEl, compareEl)));
}
0
function array_diff(a, b) {

    let array = [];
    for(let i = 0; i <a.length; i++) {
        let k = 0;
        for( let j = 0; j < b.length; j++) {
            if(a[i]!==b[j]) {
                k++;
            }
            if(k===b.length) {
                array = array.concat(a[i]);
            }
        }

        if(b.length ===0) {
            array = array.concat(a[i]);
        }
    }
    return array;
}
0
user608540
var arrayDifference = function(arr1, arr2){
  if(arr1 && arr1.length){
    if(arr2 && arr2.length > 0){
      for (var i=0, itemIndex; i<arr2.length; i++){
        itemIndex = arr1.indexOf(arr2[i]);
        if(itemIndex !== -1){
          arr1.splice(itemIndex, 1);
        }
      }
    }
    return arr1;
  }
  return [];
};

arrayDifference([1,2,3,4,5], [1,5,6]);
0
Aswin Ramesh

共通のオブジェクトを使用して、最初の配列の各値の頻度を数えることができます。 2番目の配列の場合は、共通オブジェクトの値を減らします。次に、すべてのキーを繰り返し処理し、値が1より大きいすべてのキーを追加します。

const difference = (a1, a2) => {
  var obj = {};
  a1.forEach(v => obj[v] = (obj[v] || 0) + 1);
  a2.forEach(v => obj[v] = (obj[v] || 0) - 1);
  return Object
      .keys(obj)
      .reduce((r,k) => {
        if(obj[k] > 0)
          r = r.concat(Array.from({length: obj[k]}).fill(k));
        return r;
      },[]);
};
const result = difference(['a', 'a', 'b', 'c', 'd'], ['a', 'b']);
console.log(result);
0
Hassan Imam

これが2つの配列の違いを得る方法です。清潔で清潔です。

[add list]と[remove list]を含むオブジェクトを返します。

  function getDiff(past, now) {
        let ret = { add: [], remove: [] };
        for (var i = 0; i < now.length; i++) {
          if (past.indexOf(now[i]) < 0)
            ret['add'].Push(now[i]);
        }
        for (var i = 0; i < past.length; i++) {
          if (now.indexOf(past[i]) < 0)
            ret['remove'].Push(past[i]);
        }
        return ret;
      }
0
rosethorn999

これが私が使っているものです:

var newArr = a1.filter(function(elem) {
            return a2.indexOf(elem) === -1;
        }).concat( a2.filter(function(elem) {
            return a1.indexOf(elem) === -1;
        }));
console.log(newArr);

またはこれ

var newArr = a1.concat(a2);
        function check(item) {
            if (a1.indexOf(item) === -1 || a2.indexOf(item) === -1) {
                return item;
            }
        }
        return newArr.filter(check);
0
Koushik Das

私は上記のすべてを試してみましたが、あなたが複製を受け入れることなしにマッチする必要があったとき、どれもうまくいきませんでした。

例えば:

var a1 = [1, 2, 1, 4], a2 = [1, 2, 4];

たとえ2回一致させる必要があったとしても、2は2番目の配列で1回見つかるため、空のdiff配列を返します。

だから私はなんとかして何かを直すことができました:

Array.prototype.diff = function(a) {
    return this.filter(function(item) {
        match = a.indexOf(item);
        if (match)
            a.splice(match, 1);
        return match < 0;
    });
};
0
casraf

選択された答えは右半分だけです。完全な答えを得るためには、両方の方法で配列を比較する必要があります。

const ids_exist = [
   '1234',
   '5678',
   'abcd',
]

const ids_new = [
  '1234',
  '5678',
  'efjk',
  '9999',
]

function __uniq_Filter (__array_1, __array_2) {
  const one_not_in_two = __array_1.filter(function (obj) {
    return __array_2.indexOf(obj) == -1
  })
  const two_not_in_one = __array_2.filter(function (obj) {
    return __array_1.indexOf(obj) == -1
  })
  return one_not_in_two.concat(two_not_in_one)
}

let uniq_filter = __uniq_Filter(ids_exist, ids_new)

console.log('uniq_filter', uniq_filter) // => [ 'abcd', 'efjk', '9999' ]
0
Flavio

私にとってはこれを部分的な関数として処理する方が簡単だと感じます。関数型プログラミングソリューションを見ていないことに驚いたのは、ES6の私のものです。

const arrayDiff = (a, b) => {
  return diff(b)(a);
}

const contains = (needle) => (array) => {
  for (let i=0; i < array.length; i++) {
    if (array[i] == needle) return true;
  }

  return false;
}

const diff = (compare) => {
    return (array) => array.filter((elem) => !contains(elem)(compare))
}
0
Decebal

私がここで読んでいる答えには、実用的なプログラミングアプリケーションでは価値が限られているという問題がたくさんあります。

何よりもまず、配列内の2つの項目が「等しい」ということが何を意味するのかを制御する方法が必要になります。 IDやそれに類するものに基づいてオブジェクトの配列を更新するかどうかを判断しようとしているのであれば、===比較ではうまくいかないでしょう。 diff関数また、文字列、整数など、===演算子と比較できるものの配列に限定されています。これは、大人にはほとんど受け入れられません。

次に、diff操作の結果は3つあります。

  1. 最初の配列にはあるが2番目の配列にはない要素
  2. 両方の配列に共通の要素
  3. 2番目の配列にはあるが最初の配列にはない要素

私はこれがあなたが2つ以上のループを必要とすることを意味すると思います、しかし誰かがそれを1に減らす方法を知っているならば汚いトリックに開放されています。

これは私が一緒に石畳にしたものです、そして、私はそれがMicroshaftブラウザの古いバージョンで働かないということを絶対に気にしないことを強調したいです。あなたがIEのような劣ったコーディング環境で働いているならば、あなたが立ち往生している不満足な制限内で働くようにそれを修正するのはあなた次第です。

Array.defaultValueComparison = function(a, b) {
    return (a === b);
};

Array.prototype.diff = function(arr, fnCompare) {

    // validate params

    if (!(arr instanceof Array))
        arr = [arr];

    fnCompare = fnCompare || Array.defaultValueComparison;

    var original = this, exists, storage, 
        result = { common: [], removed: [], inserted: [] };

    original.forEach(function(existingItem) {

        // Finds common elements and elements that 
        // do not exist in the original array

        exists = arr.some(function(newItem) {
            return fnCompare(existingItem, newItem);
        });

        storage = (exists) ? result.common : result.removed;
        storage.Push(existingItem);

    });

    arr.forEach(function(newItem) {

        exists = original.some(function(existingItem) {
            return fnCompare(existingItem, newItem);
        });

        if (!exists)
            result.inserted.Push(newItem);

    });

    return result;

};
0
Mason Houtz

データ:

var new_storage = JSON.parse('[{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0006"}]');

var old_storage = JSON.parse('[{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0005"}]');

フィルタを使う:

var diff = new_storage
.filter(x => {if(!(old_storage.filter(y => y.id_order==x.id_order)).length){return x}})
    .concat(old_storage
    .filter(x => {if(!(new_storage.filter(y => y.id_order==x.id_order)).length){return x}})
                       ) 

console.log(JSON.stringify(diff))

2つの配列の結果の違い

[{"id_order":"0006"},{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0005"}]
0
uscamayta

**これは、 'type'引数に基づく2つの配列に対して、一意の値の配列、重複の配列、または重複しない配列(違い)の配列を返します。 **

let json1 = ['one', 'two']
let json2 = ['one', 'two', 'three', 'four']

function uniq_n_shit (arr1, arr2, type) {

  let concat = arr1.concat(arr2)
  let set = [...new Set(concat)]

  if (!type || type === 'uniq' || type === 'unique') {

    return set

  } else if (type === 'duplicate') {

    concat = arr1.concat(arr2)
    return concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

  } else if (type === 'not_duplicate') {

    let duplicates = concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

    for (let r = 0; r < duplicates.length; r++) {
      let i = set.indexOf(duplicates[r]);
      if(i !== -1) {
        set.splice(i, 1);
      }
    }

    return set

  }
}

console.log(uniq_n_shit(json1, json2, null)) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'uniq')) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'duplicate')) // => [ 'one', 'two' ]
console.log(uniq_n_shit(json1, json2, 'not_duplicate')) // => [ 'three', 'four' ]
0
Flavio

確認するために文字列をトリミングするだけです。スペースは差分に影響しません

function arr_diff(a1, a2) {
    var a=[], diff=[];
    for(var i=0;i<a1.length;i++)
        a[a1[i]]=true;
    for(var i=0;i<a2.length;i++)
        if(a[a2[i].trim()]) delete a[a2[i].trim()];
    else a[a2[i].trim()]=true;
    for(var k in a)
        diff.Push(k);
    return diff;
}
0
Sivanagaiah