有没有一种方法可以在 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"]
有一种更好的方法,使用ES7:
交集
let intersection = arr1.filter(x => arr2.includes(x));
对于[1,2,3] [2,3]
,它将产生[2,3]
。另一方面,对于[1,2,3] [2,3,5]
将返回相同的结果。
差异
let difference = arr1.filter(x => !arr2.includes(x));
对于 [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)));
这样,你将得到一个包含 arr1 中所有不在 arr2 中的元素以及反之的数组。
正如 @Joshaven Potter 在他的答案中指出的那样,你可以将这个方法添加到 Array.prototype 中,这样就可以像这样使用:
Array.prototype.diff = function(arr2) { return this.filter(x => !arr2.includes(x)); }
[1, 2, 3].diff([2, 3])
Set
的独特职责,而Set
比indexOf
/includes
快得多。简单来说,你的解决方案非常低效,而且相对较慢。 - user6445533Set
,值必须是唯一的,对吗? - CervEd[1,2,3] [2,3,5]
这组数据会奏效,但如果你有[1,1,2,3] [1,2,3,5]
并期望得到[1]
,你不能使用Set
。虽然你的解决方案也行不通 :-/ 我最终创建了这个函数,因为我找不到更简洁的方法来完成它。如果你有任何想法,我很乐意知道! - CervEdArray.includes()
不是ES6功能,而是ES7功能 (1) (2)。因此,在ES6中,您可以使用Array.some()
。例如,您可以使用以下代码来获取两个数组的交集 let intersection = aArray.filter(a => bArray.some(b => a === b))
。 - Jari KeinänenArray.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
//////////////
// Examples //
//////////////
const dif1 = [1,2,3,4,5,6].diff( [3,4,5] );
console.log(dif1); // => [1, 2, 6]
const dif2 = ["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);
console.log(dif2); // => ["test5", "test6"]
注意:.indexOf()
和.filter()
在IE9之前不可用。
[1,2,3].diff([3,4,5])
,它会返回[1,2]
而不是[1,2,4,5]
,因此它不能解决原问题,需要注意。 - Bugster这个回答是在2009年写的,所以有点过时,也更适合理解问题。我今天会使用的最佳解决方案是
let difference = arr1.filter(x => !arr2.includes(x));
(感谢其他作者)
我假设你正在比较一个普通的数组。如果不是,请将 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"));
var a1 = ['a', 'b'];
和 var a2 = ['a', 'b', 'c', 'd', 'b'];
后,当试图在 a2
数组中使用 filter()
方法过滤出不包含在 a1
数组中的元素时,结果会返回错误答案 ['c', 'd', 'b']
而不是正确答案 ['c', 'd']
。 - skbly7if (!la) return b;
else if (!lb) return a;
for (i = 0; i < la; i++) {
if (b.indexOf(a[i]) === -1) res.push(a[i]);
}
for (i = 0; i < lb; i++) {
if (a.indexOf(b[i]) === -1) res.push(b[i]);
}
return res;
}` - nomæd使用jQuery是迄今为止获得您要寻找的确切结果最简单的方法:
var diff = $(old_array).not(new_array).get();
diff
现在包含了 old_array
中不在 new_array
中的内容。
.not
时,jQuery会使用其内置的实用程序.grep()
来过滤数组。我认为这种情况不会改变。 - superphonicO(m x n)
吗,其中 m
是 old_array
的长度,n
是 new_array
的长度? - RaulUnderscore(或其替代品Lo-Dash)中的difference方法也可以实现此功能:
(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]);
"difference"有两种可能的解释,你可以选择其中一种。比如说你有:
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,您可以使用_.difference(a1, a2)
(第一种情况)或_.xor(a1, a2)
(第二种情况)。
如果您正在使用Underscore.js,则可以使用_.difference(a1, a2)
函数处理第一种情况。
Set
对象来加速。当Set
可用时,Lodash会自动使用它。如果您没有使用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
来解决这个问题的事实令人惊讶。 - Aaron BeaudoinES6中更优雅的方法如下所示。
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
a2.filter(d => !a1.includes(d)) // gives ["c", "d"]
a2.filter(d => a1.includes(d)) // gives ["a", "b"]
[ ...a2.filter(d => !a1.includes(d)),
...a1.filter(d => !a2.includes(d)) ]
a1 = ['a', 'b', 'e']
:e 将不会被提取。 - imrok为了得到对称差集,需要比较两个数组(或在多个数组的情况下比较所有数组)。
// 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));
}));
}
// 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);
}));
}
// 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}]
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}
const unique = (a) => [...new Set(a)];
const uniqueBy = (x,f)=>Object.values(x.reduce((a,b)=>((a[f(b)]=b),a),{}));
const intersection = (a, b) => a.filter((v) => b.includes(v));
const diff = (a, b) => a.filter((v) => !b.includes(v));
const symDiff = (a, b) => diff(a, b).concat(diff(b, a));
const union = (a, b) => diff(a, b).concat(b);
const a = unique([1, 2, 3, 4, 5, 5]);
console.log(a);
const b = [4, 5, 6, 7, 8];
console.log(intersection(a, b), diff(a, b), symDiff(a, b), union(a, b));
console.log(uniqueBy(
[
{ id: 1, name: "abc" },
{ id: 2, name: "xyz" },
{ id: 1, name: "abc" },
],
(v) => v.id
));
const intersectionBy = (a, b, f) => a.filter((v) => b.some((u) => f(v, u)));
console.log(intersectionBy(
[
{ id: 1, name: "abc" },
{ id: 2, name: "xyz" },
],
[
{ id: 1, name: "abc" },
{ id: 3, name: "pqr" },
],
(v, u) => v.id === u.id
));
const diffBy = (a, b, f) => a.filter((v) => !b.some((u) => f(v, u)));
console.log(diffBy(
[
{ id: 1, name: "abc" },
{ id: 2, name: "xyz" },
],
[
{ id: 1, name: "abc" },
{ id: 3, name: "pqr" },
],
(v, u) => v.id === u.id
));
const unique = <T>(array: T[]) => [...new Set(array)];
const intersection = <T>(array1: T[], array2: T[]) =>
array1.filter((v) => array2.includes(v));
const diff = <T>(array1: T[], array2: T[]) =>
array1.filter((v) => !array2.includes(v));
const symDiff = <T>(array1: T[], array2: T[]) =>
diff(array1, array2).concat(diff(array2, array1));
const union = <T>(array1: T[], array2: T[]) =>
diff(array1, array2).concat(array2);
const intersectionBy = <T>(
array1: T[],
array2: T[],
predicate: (array1Value: T, array2Value: T) => boolean
) => array1.filter((v) => array2.some((u) => predicate(v, u)));
const diffBy = <T>(
array1: T[],
array2: T[],
predicate: (array1Value: T, array2Value: T) => boolean
) => array1.filter((v) => !array2.some((u) => predicate(v, u)));
const uniqueBy = <T>(
array: T[],
predicate: (v: T, i: number, a: T[]) => string
) =>
Object.values(
array.reduce((acc, value, index) => {
acc[predicate(value, index, array)] = value;
return acc;
}, {} as { [key: string]: T })
);
O(a1.length x log(a2.length))
- 这种性能在JavaScript中是否可能? - Raul