是否有一种方法可以在JavaScript中返回两个数组之间的差异?
例如:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
是否有一种方法可以在JavaScript中返回两个数组之间的差异?
例如:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
当前回答
纯JavaScript
对于“差异”有两种可能的解释。我让你选你想要的。假设你有:
var a1 = ['a', 'b' ];
var a2 = [ 'b', 'c'];
If you want to get ['a'], use this function: 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; } If you want to get ['a', 'c'] (all elements contained in either a1 or a2, but not both -- the so-called symmetric difference), use this function: 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,你可以使用_。差异(a1, a2)(上述情况1)或_。Xor (a1, a2)(情形2)
如果你使用的是Underscore.js,你可以使用_。情况1的差分(a1, a2)函数。
ES6 Set,用于非常大的数组
上面的代码适用于所有浏览器。然而,对于超过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或稀疏数组,那么所有示例的行为都可能令人惊讶或不明显。(对于大多数用途来说,这并不重要。)
其他回答
这是受到了思想者接受的答案的启发,但是思想者的答案似乎假设数组是集合。如果数组是["1","2"]和["1","1","2","2"],它就不成立了
这些数组之间的差值是["1","2"]。下面的解决方案是O(n*n),所以不理想,但如果您有大数组,它也比思想者的解决方案具有内存优势。
如果你首先处理的是集合,思想者的解决方案肯定更好。如果你有一个可以访问过滤器的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;
}
}
这个怎么样:
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。长度(我相信)
这个答案是2009年写的,所以有点过时了,但是对于理解这个问题还是很有教育意义的。我今天最好的解决办法是
let difference = arr1.filter(x => !arr2.includes(x));
(此处致谢给其他作者)
我假设你比较的是一个普通数组。如果不是,你需要将for循环改为for ..在循环。
函数arr_diff (a1, a2) { Var a = [], diff = []; For (var I = 0;I < a1.length;我+ +){ A [a1[i]] = true; } For (var I = 0;I < a2.length;我+ +){ If (a[a2[i]]) { 删除一个[a2[我]]; }其他{ A [a2[i]] = true; } } 对于(var k in a) { diff.push (k); } 返回差异; } console.log (arr_diff ([a, b], [a, b, c, d '))); console.log (arr_diff(“abcd”、"中的")); console.log (arr_diff(“必杀技”,“必杀技”));
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)));
}
使用ES7有一个更好的方法:
十字路口
let intersection = arr1.filter(x => arr2.includes(x));
对于[1,2,3][2,3],它将生成[2,3]。另一方面,for[1,2,3][2,3,5]将返回相同的结果。
区别
let difference = arr1.filter(x => !arr2.includes(x));
对于[1,2,3][2,3],它将生成[1]。另一方面,for[1,2,3][2,3,5]将返回相同的结果。
对于对称差分,你可以这样做:
let difference = arr1
.filter(x => !arr2.includes(x))
.concat(arr2.filter(x => !arr1.includes(x)));
通过这种方式,您将得到一个包含arr1中所有不在arr2中的元素的数组,反之亦然
正如@Joshaven Potter在他的回答中指出的,你可以把这个添加到Array中。原型,所以它可以这样使用:
Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])