如何在JavaScript中获取两个数组之间的差异?

1333

有没有一种方法可以在 JavaScript 中返回两个数组的差异?

例如:

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

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

16
对称还是非对称? - Lightness Races in Orbit
2
使用新的ES6函数,这可以作为一个简单的一行代码完成(在所有主要浏览器中使用它需要很长时间)。无论如何,请查看我的答案 - Salvador Dali
2
解决方案的一个重要方面是性能。这种类型操作的渐进时间复杂度 - 在其他语言中 - 是 O(a1.length x log(a2.length)) - 这种性能在JavaScript中是否可能? - Raul
请查看我的库,它可以帮助您解决这个问题,@netilon/differify 是用于对象/数组比较的最快速的差异库之一: https://www.npmjs.com/package/@netilon/differify - Fabian Orue
1
  1. 将a1转换为集合。o(a1)。
  2. 迭代e2以查看它具有而e1没有的内容。o(e2)。
  3. 将差异推入另一个数组,然后在完成步骤2后返回它。
- powerup7
您可以使用筛选器,检查我的答案https://dev59.com/aXM_5IYBdhLWcg3w3nbz#74317431 - Manu Rastogi
84个回答

6
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

这对我很有效


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

const diffArr = a1.filter(o => !a2.includes(o));

console.log(diffArr);

输出:

[ 'a', 'b' ]

1
这只是检查相似性,而不是差异。应该是!a2.includes(o)。如果您不介意的话,我已经编辑了您的答案... - Korayem
3
输出应为['c','d']而不是['a','b']。 - Erdogan ABACI

6
这个怎么样:
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))


使用过滤选项是个好主意... 但是,你不需要为数组创建一个包含方法。我把你的想法转化成了一行代码... 感谢你的启发! - Joshaven Potter
你不需要定义contains()函数。JS的includes()函数可以实现相同的功能。 - Da Man

5

查找没有重复的两个数组之间的差异

function difference(arr1, arr2){

  let setA = new Set(arr1);
  let differenceSet = new Set(arr2.filter(ele => !setA.has(ele)));
  return [...differenceSet ];

}

1. difference([2,2,3,4],[2,3,3,4])将返回[]

2. difference([1,2,3],[4,5,6])将返回[4,5,6]

3. difference([1,2,3,4],[1,2])将返回[]

4. difference([1,2],[1,2,3,4])将返回[3,4]

注意:上述解决方案要求您始终将更大的数组作为第二个参数发送。 要找到两个数组的绝对差异,您需要先找到两个数组中较大的那一个,然后处理它们。

要查找没有重复项的2个数组的绝对差异

function absDifference(arr1, arr2){

  const {larger, smaller} = arr1.length > arr2.length ? 
  {larger: arr1, smaller: arr2} : {larger: arr2, smaller: arr1}
  
  let setA = new Set(smaller);
  let absDifferenceSet = new Set(larger.filter(ele => !setA.has(ele)));
  return [...absDifferenceSet ];

}

1.absDifference([2,2,3,4],[2,3,3,4])将返回[]

2.absDifference([1,2,3],[4,5,6])将返回[4,5,6]

3.absDifference([1,2,3,4],[1,2])将返回[3,4]

4.absDifference([1,2],[1,2,3,4])将返回[3,4]

请注意这两个解决方案中的示例3


4
使用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

这里还有另一种解决方案,可以像git diff一样返回差异(已经用typescript编写了,如果您没有使用typescript版本,只需删除类型即可)

/**
 * util function to calculate the difference between two arrays (pay attention to 'from' and 'to'),
 * it would return the mutations from 'from' to 'to' 
 * @param { T[] } from
 * @param { T[] } to
 * @returns { { [x in string]: boolean } } it would return the stringified version of array element, true means added,
 * false means removed
 */
export function arrDiff<T>(from: T[], to: T[]): { [x in string]: boolean } {

  var diff: { [x in string]: boolean } = {};
  var newItems: T[] = []
  diff = from.reduce((a, e) => ({ ...a, [JSON.stringify(e)]: true }), {})

  for (var i = 0; i < to.length; i++) {
    if (diff[JSON.stringify(to[i])]) {
      delete diff[JSON.stringify(to[i])]
    } else {
      newItems.push(to[i])
    }
  }

  return {
    ...Object.keys(diff).reduce((a, e) => ({ ...a, [e]: false }), {}),
    ...newItems.reduce((a, e) => ({ ...a, [JSON.stringify(e)]: true }), {})
  }
}

这里是一个使用示例:

arrDiff(['a', 'b', 'c'], ['a', 'd', 'c', 'f']) //{"b": false, "d": true, "f": true}

4
  • 纯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(', ')
);


你可以缓存长度值以获得更快的速度。我想建议在访问数组元素时不要检查长度,但显然这个简单的检查可以使速度提高近100倍。 - Slotos
没有必要缓存 length 值。它已经是一个普通属性了。https://jsperf.com/array-length-caching - vp_arth

3

对称复杂度线性复杂度。需要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));
}

3

试一下。

var first = [ 1, 2, 3, 4, 5 ];
    var second = [ 4, 5, 6 ];
     
    var difference = first.filter(x => second.indexOf(x) === -1);
    console.log(difference);


Output: [ 1, 2, 3]

var first = [ 1, 2, 3, 4, 5 ];
    var second = [ 4, 5, 6 ];
     
    var difference = first.filter(x => second.indexOf(x) === -1);
    console.log(difference);


1
这不是正确的。请尝试var first = [4, 5, 6];var second = [1, 2, 3, 4, 5, 6]; - Matt

3
const dbData = [{name:'ally'}, 
{name:'James'}]
const localData = [{name:'James'}] 

const diff = dbData.filter(a =>!localData.some(b => { return a.name === b.name}))

3
虽然这段代码可能会回答问题,但提供有关如何以及/或为什么解决问题的附加上下文将改善答案的长期价值。您可以在帮助中心中找到有关如何编写良好答案的更多信息:https://stackoverflow.com/help/how-to-answer。祝好运。 - nima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接