如何获得两个数组之间的差异?

有没有办法在JavaScript中返回两个数组之间的区别?

例如:

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

任何build议不胜感激。

我假设你正在比较一个正常的数组。 如果不是,则需要将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; }; 

一个更好的解决scheme,如果你不关心向后兼容性,正在使用filter。 但是,这个解决scheme仍然有效,所以投票是不公平的。

 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"] 

注意 indexOf和filter在ie9之前是不可用的。

这是迄今为止使用jQuery获得准确结果的最简单的方法:

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

diff现在包含old_array中不在new_array

有一个更好的方法使用ES6:

 let difference = arr1.filter(x => arr2.indexOf(x) == -1); 

在这里输入图像描述

对于[1,2,3] [2,3]它将产生[1] 。 另一方面,对于[1,2,3] [2,3,5]将返回相同的东西。

对于一个对称的区别 ,你可以这样做:

 let difference = arr1 .filter(x => arr2.indexOf(x) == -1) .concat(arr2.filter(x => arr1.indexOf(x) == -1)); 

在这里输入图像描述

这样,你将得到一个包含arr1中所有不在arr2中的元素的数组,反之亦然

在Underscore (或其替代品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] 

与任何Underscore函数一样,您也可以使用更多面向对象的风格:

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

普通的JavaScript

对“差异”有两种可能的解释。 我会让你select你想要的。 假设你有:

 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'] (包含在a1a2所有元素,但不是两个 – 所谓的对称差异 ),使用这个函数:

     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 /下划线

如果您使用lodash,则可以使用_.difference(a1, a2) (上面的情况1)或_.xor(a1, a2) (情况2)。

如果您使用的是_.difference(a1, a2) ,则可以对情况1使用_.difference(a1, a2)函数。

ES6 Set,用于非常大的数组

上面的代码适用于所有浏览器。 然而,对于超过10,000个物品的大型数组,它变得非常慢,因为它具有O(n 2)的复杂性。 在许多现代浏览器上,我们可以利用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或稀疏数组,则所有示例的行为可能会令人惊讶或不明显。 (对于大多数用途,这并不重要。)

在这种情况下你可以使用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} 

从另一个数组中减去一个数组,只需使用下面的代码片段:

 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; }); 

它会返回['1,'2','6'],它们是第一个数组中不存在的第一个数组的项目。

因此,根据您的问题示例,下面的代码是确切的解决scheme:

 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; }); 
 function diff(a1, a2) { return a1.concat(a2).filter(function(val, index, arr){ return arr.indexOf(val) === arr.lastIndexOf(val); }); } 

合并这两个数组,唯一值只会出现一次,所以indexOf()将和lastIndexOf()相同。

对于小数组,使用indexOf()解决scheme是可以的,但是随着它们长度的增长,algorithm的性能接近O(n^2) 。 下面是一个解决scheme,通过使用对象作为关联数组来存储数组条目作为关键字,可以更好地处理非常大的数组。 它也自动消除了重复的条目,但只适用于string值(或可以安全地存储为string的值):

 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'] 

Joshaven Potter的上述答案很好。 但它返回数组B中不在数组C中的元素,但不是相反的。 例如,如果var a=[1,2,3,4,5,6].diff( [3,4,5,7]); 那么它会输出:==> [1,2,6] ,但不是 [1,2,6,7] ,这是两者之间的实际差异。 你仍然可以使用上面的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 ]

随着ES6的到来,集合和splat操作符(仅在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" ]

function方法与ES2015

计算两个数组之间的differenceSet操作之一。 该术语已经表明应该使用本机Settypes,以提高查找速度。 无论如何,当你计算两组之间的差异时,有三种排列:

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

这是反映这些排列的function性解决scheme。

左派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) ); 

解决问题的另一种方法

 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] 
 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] 

非常简单的解决scheme与JavaScript的过滤function:

 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); 

使用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"] 

这个怎么样:

 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)来获得它们的区别(algorithm的可怕时间复杂度虽然 – O(array1.length x array2.length)我相信)

这是工作:基本上合并两个数组,寻找重复,并推动什么是不重复到一个新的数组,这是不同的。

 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; } 
 function diffArray(arr1, arr2) { var newArr = arr1.concat(arr2); return newArr.filter(function(i){ return newArr.indexOf(i) == newArr.lastIndexOf(i); }); } 

这对我很有用

只是想…为了挑战的缘故;-)会这样做…(对于基本的string,数字等数组)没有嵌套的数组

 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"] 

注意sorting可能不会如上所述……但如果需要,可以调用数组中的.sort()进行sorting。

littlebit修复最好的答案

 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; } 

这将考虑当前types的元素。 b / c当我们做一个[a1 [i]]它将一个值转换成string的值,所以我们失去了实际价值。

  • 纯JavaScript解决scheme(无库)
  • 与旧版浏览器兼容(不使用filter
  • 为O(n ^ 2)
  • 可选的fncallback参数,可以指定如何比较数组项目
 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(', ') ); 
 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] 

我想要一个类似的函数,它接受了一个旧的数组和一个新的数组,并给了我一个添加项目和一个被删除项目的数组,并且我希望它是高效的(所以没有.contains!)。

你可以在这里玩我提出的解决scheme: http : //jsbin.com/osewu3/12 。

任何人都可以看到任何问题/该algorithm的改进? 谢谢!

代码清单:

 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}; } 

我正在寻找一个简单的答案,不涉及使用不同的图书馆,我想出了我自己,我不认为这里已经提到。 我不知道它是多么的有效率,但它是有效的。

  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; } 

对于我的代码,我需要重复取出,但我想这并不总是首选。

我想主要的缺点是它可能比较已经被拒绝的许多选项。

为了回应那个想从另一个数组中减去一个数组的人

如果不超过说1000个元素试试这个…

设置一个新variables来复制Array01并将其称为Array03。

现在,使用冒泡sortingalgorithm来比较Array01和Array02的元素,每当你发现一个匹配时,对Array03执行以下操作…

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

NB:我们正在修改Array03而不是Array01,以免搞乱气泡sorting的嵌套循环!

最后,用一个简单的赋值将Array03的内容复制到Array01,就完成了。

你可以使用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] 

如果不使用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; } 

贡献一个我目前使用的jQuery解决scheme:

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