如何在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个回答

2

如果数组不是简单类型,则可以调整上述任一答案:

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

类似于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' ] 
// }

2

最佳答案的小修复

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

这将考虑当前元素的类型。因为当我们使用a[a1[i]]时,它会将一个值从其原始值转换为字符串,所以我们失去了实际值。


这对于对象数组仍然无法实现。var a = [{a: 1}], b = [{b: 2}] arr_diff(a,b) == []。 - EricP

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

第一个例子对于字符串数组非常好用。谢谢@fog。 - Dennis V

2

快速解决方案。虽然似乎其他人已经发布了不同变化的同一方法,但我不确定这对于巨大的数组来说是否是最好的,但它适用于我的数组,这些数组不会超过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);
    }
  }
}

2
这受到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
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]);
}

那很简单。也可以与对象一起使用,检查对象的一个属性。 例如:
if (a2[i].id === a1[j].id) found = true;

1

CoffeeScript版本:

diff = (val for val in array1 when val not in array2)

1
所选答案只有一半是正确的。您必须双向比较数组才能得到完整的答案。
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' ]

1
    function arrayDiff(a, b) {
      return a.concat(b).filter(val => !(b.includes(val)));
      //(or) return a.concat(b).filter(val => !(a.includes(val) && b.includes(val)));
    }

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