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

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

例如:

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

// need ["c", "d"]
Davaid泡芙2020/03/11 14:32:45

littlebit fix for the best answer

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

this will take current type of element in consideration. b/c when we make a[a1[i]] it converts a value to string from its oroginal value, so we lost actual value.

蛋蛋Near2020/03/11 14:32:45

You can use underscore.js : http://underscorejs.org/#intersection

You have needed methods for array :

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

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
Tony伽罗Sam2020/03/11 14:32:45

Just thinking... for the sake of a challenge ;-) would this work... (for basic arrays of strings, numbers, etc.) no nested arrays

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

Note the sorting will likely not be as noted above... but if desired, call .sort() on the array to sort it.

2020/03/11 14:32:45

This is working: basically merge the two arrays, look for the duplicates and push what is not duplicated into a new array which is the difference.

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

路易EvaSam2020/03/11 14:32:45

Symmetric and linear complexity. Requires 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));
}
老丝飞云2020/03/11 14:32:45

yet another answer, but seems nobody mentioned jsperf where they compare several algorithms and technology support: https://jsperf.com/array-difference-javascript seems using filter gets the best results. thanks

SamEva2020/03/11 14:32:45
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

this is works for me

阿飞神奇2020/03/11 14:32:45

Using http://phrogz.net/JS/ArraySetMath.js you can:

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"]
逆天Near2020/03/11 14:32:45

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 ]

前端凯2020/03/11 14:32:45
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]
神奇JinJin2020/03/11 14:32:45

这个怎么样:

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)

JinJin伽罗小胖2020/03/11 14:32:45

解决问题的另一种方法

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]

另外,您可以使用箭头函数语法:

const diffArray = (arr1, arr2) => arr1.concat(arr2)
    .filter(val => !(arr1.includes(val) && arr2.includes(val)));

diffArray([1, 2, 3, 7], [3, 2, 1, 4, 5]);    // return [7, 4, 5]
神奇启人2020/03/11 14:32:44
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

合并两个数组,唯一值将仅出现一次,因此indexOf()将与lastIndexOf()相同。

番长阳光2020/03/11 14:32:44

ES2015的功能性方法

计算difference两个数组之间的和是Set操作之一。该术语已经表明Set应该使用本机类型,以提高查找速度。无论如何,当您计算两组之间的差异时,存在三个排列:

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

这是一个反映这些排列的功能解决方案。

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

difference

differencer是微不足道的。它只是differencel带有翻转的参数。为了方便起见,您可以编写一个函数:const differencer = flip(differencel)就这样!

对称的difference

现在我们有了左右一个,实现对称也difference变得很简单:

// small, reusable auxiliary functions

const apply = f => x => f(x);
const flip = f => y => x => f(x) (y);
const concat = y => xs => xs.concat(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);
};


// symmetric difference

const difference = ys => xs =>
 concat(differencel(xs) (ys)) (flip(differencel) (xs) (ys));

// 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( difference(xs) (ys) );

我想这个例子是一个很好的起点,可以使人对函数式编程的印象:

使用可以以许多不同方式连接在一起的构件块进行编程。

宝儿理查德2020/03/11 14:32:44

在这种情况下,您可以使用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}
小胖Eva2020/03/11 14:32:44

到目前为止,这是使用jQuery精确获得所需结果的最简单方法:

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

diff现在包含的内容old_array不在其中new_array

前端LEY米亚2020/03/11 14:32:44

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]);
Green猴子2020/03/11 14:32:44
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"]

Array.prototype.diff = function(a) {
    return this.filter(function(i) {return a.indexOf(i) < 0;});
};

////////////////////  
// Examples  
////////////////////

var dif1 = [1,2,3,4,5,6].diff( [3,4,5] );  
console.log(dif1); // => [1, 2, 6]


var dif2 = ["test1", "test2","test3","test4","test5","test6"].diff(["test1","test2","test3","test4"]);  
console.log(dif2); // => ["test5", "test6"]

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

老丝飞云2020/03/11 14:32:44

使用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.prototype中,以便可以这样使用:

Array.prototype.diff = function(arr2) { return this.filter(x => arr2.includes(x)); }
[1, 2, 3].diff([2, 3])