1097

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

例如:

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

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

79 回答 79

2308

使用 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])
于 2015-10-09T09:33:10.723 回答
948

Array.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()IE9之前.filter()不可用。

于 2010-10-26T18:34:42.387 回答
319

这个答案是在 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"));

于 2009-07-27T11:20:33.540 回答
311

这是迄今为止使用 jQuery 获得您正在寻找的结果的最简单方法:

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

diff现在包含在里面的东西old_array不在里面new_array

于 2013-03-13T12:57:04.890 回答
174

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]);
于 2012-07-05T22:44:52.087 回答
89

纯 JavaScript

“差异”有两种可能的解释。我会让你选择你想要的。假设你有:

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
  1. 如果你想得到['a'],使用这个函数:

    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;
    }
    
  2. 如果你想得到(包含在一个['a', 'c']中的所有元素,但不是两个——所谓的对称差),使用这个函数: a1a2

    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 / 下划线

如果您使用的是 lodash,则可以使用_.difference(a1, a2)(上面的案例 1) 或_.xor(a1, a2)(案例 2)。

如果您使用的是 Underscore.js,则可以使用_.difference(a1, a2)案例 1 的函数。

ES6 Set,用于非常大的数组

上面的代码适用于所有浏览器。然而,对于超过 10,000 个项目的大型数组,它变得相当慢,因为它具有 O(n²) 复杂度。在许多现代浏览器上,我们可以利用 ES6Set对象来加快速度。LodashSet会在可用时自动使用。如果您不使用 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或稀疏数组,所有示例的行为都可能令人惊讶或不明显。(对于大多数用途,这无关紧要。)

于 2015-05-17T16:01:29.743 回答
68

ES6 中一种更简洁的方法是以下解决方案。

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)) ]
于 2020-01-26T19:41:35.307 回答
64

要获得对称差异,您需要以两种方式比较数组(或者在多个数组的情况下以所有方式)

在此处输入图像描述


ES7(ECMAScript 2016)

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

ES6(ECMAScript 2015)

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

ES5 (ECMAScript 5.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}]
于 2018-09-20T17:04:38.700 回答
53

在这种情况下,您可以使用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}
于 2009-07-27T10:43:55.877 回答
33
function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}

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

于 2015-06-30T14:33:56.300 回答
28

随着带有集合和 splat 运算符的 ES6 的到来(当时仅在 Firefox 中有效,请检查兼容性表),您可以编写以下一行:

var a = ['a', 'b', 'c', 'd'];
var b = ['a', 'b'];
var b1 = new Set(b);
var difference = [...new Set(a.filter(x => !b1.has(x)))];

这将导致[ "c", "d" ].

于 2015-01-17T07:15:09.227 回答
18

要从另一个数组中减去一个数组,只需使用以下代码段:

var a1 = ['1','2','3','4','6'];
var a2 = ['3','4','5'];

var items = new Array();

items = jQuery.grep(a1,function (item) {
    return jQuery.inArray(item, a2) < 0;
});

它将返回 ['1,'2','6'] ,它们是第一个数组中不存在于第二个数组中的项。

因此,根据您的问题示例,以下代码是确切的解决方案:

var array1 = ["test1", "test2","test3", "test4"];
var array2 = ["test1", "test2","test3","test4", "test5", "test6"];

var _array = new Array();

_array = jQuery.grep(array2, function (item) {
     return jQuery.inArray(item, array1) < 0;
});
于 2011-11-21T11:26:17.967 回答
16

解决问题的另一种方法

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]
于 2016-11-01T21:47:00.593 回答
15

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

我想这个例子是了解函数式编程意味着什么的一个很好的起点:

使用可以以多种不同方式插入在一起的构建块进行编程。

于 2016-10-11T16:00:30.253 回答
13

一班轮

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

于 2021-09-27T17:22:16.047 回答
12

indexOf()使用小数组的解决方案是可以的,但随着它们长度的增长,算法的性能会接近O(n^2)。这是一个解决方案,通过使用对象作为关联数组将数组条目存储为键,对于非常大的数组表现更好;它还自动消除重复条目,但仅适用于字符串值(或可以安全存储为字符串的值):

function arrayDiff(a1, a2) {
  var o1={}, o2={}, diff=[], i, len, k;
  for (i=0, len=a1.length; i<len; i++) { o1[a1[i]] = true; }
  for (i=0, len=a2.length; i<len; i++) { o2[a2[i]] = true; }
  for (k in o1) { if (!(k in o2)) { diff.push(k); } }
  for (k in o2) { if (!(k in o1)) { diff.push(k); } }
  return diff;
}

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
arrayDiff(a1, a2); // => ['c', 'd']
arrayDiff(a2, a1); // => ['c', 'd']
于 2012-05-15T15:22:23.053 回答
10

Joshaven Potter 的上述回答很棒。但它返回数组 B 中不在数组 C 中的元素,但反之则不然。例如,如果var a=[1,2,3,4,5,6].diff( [3,4,5,7]);then 它将输出: ==> [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 ]

于 2012-09-20T18:27:32.293 回答
8

带有 JavaScript 过滤功能的非常简单的解决方案:

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

function diffArray(arr1, arr2) {
  var newArr = [];
  var myArr = arr1.concat(arr2);
  
    newArr = myArr.filter(function(item){
      return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
    });
   alert(newArr);
}

diffArray(a1, a2);

于 2017-04-11T21:56:49.117 回答
7
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]
于 2015-07-07T14:55:28.360 回答
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) 我相信)

于 2010-08-05T21:10:26.163 回答
6
function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}

这对我有用

于 2016-05-05T14:24:28.967 回答
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"]
于 2011-01-25T18:21:10.997 回答
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(', ')
);

于 2014-09-17T19:57:48.113 回答
4

要查找没有重复的 2 个数组的差异:

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

于 2021-02-03T21:40:03.807 回答
3

我想要一个类似的函数,它接收一个旧数组和一个新数组,并给我一个添加项数组和一个删除项数组,我希望它高效(所以没有 .contains!)。

您可以在这里使用我提出的解决方案:http: //jsbin.com/osewu3/12

任何人都可以看到该算法的任何问题/改进吗?谢谢!

代码清单:

function diff(o, n) {
  // deal with empty lists
  if (o == undefined) o = [];
  if (n == undefined) n = [];

  // sort both arrays (or this won't work)
  o.sort(); n.sort();

  // don't compare if either list is empty
  if (o.length == 0 || n.length == 0) return {added: n, removed: o};

  // declare temporary variables
  var op = 0; var np = 0;
  var a = []; var r = [];

  // compare arrays and add to add or remove lists
  while (op < o.length && np < n.length) {
      if (o[op] < n[np]) {
          // push to diff?
          r.push(o[op]);
          op++;
      }
      else if (o[op] > n[np]) {
          // push to diff?
          a.push(n[np]);
          np++;
      }
      else {
          op++;np++;
      }
  }

  // add remaining items
  if( np < n.length )
    a = a.concat(n.slice(np, n.length));
  if( op < o.length )
    r = r.concat(o.slice(op, o.length));

  return {added: a, removed: r}; 
}
于 2010-08-13T12:07:33.277 回答
3

您可以使用 underscore.js:http ://underscorejs.org/#intersection

您需要数组的方法:

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

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
于 2012-09-27T08:55:43.443 回答
3

这是有效的:基本上合并两个数组,查找重复项并将未重复的内容推送到一个新数组中,这就是区别。

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

于 2015-08-01T10:33:24.383 回答
3

//es6 方法

function diff(a, b) {
  var u = a.slice(); //dup the array
  b.map(e => {
    if (u.indexOf(e) > -1) delete u[u.indexOf(e)]
    else u.push(e)   //add non existing item to temp array
  })
  return u.filter((x) => {return (x != null)}) //flatten result
}
于 2017-08-04T20:54:07.730 回答
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));
}
于 2018-05-17T00:07:32.837 回答
3

还有另一个答案,但似乎没有人提到 jsperf,他们比较了几种算法和技术支持:https ://jsperf.com/array-difference-javascript 似乎使用过滤器得到了最好的结果。谢谢

于 2019-05-17T12:15:26.667 回答
3

使用额外的内存来执行此操作。这样你就可以用更少的时间复杂度来解决它,O(n) 而不是 o(n*n)。

function getDiff(arr1,arr2){
let k = {};
let diff = []
arr1.map(i=>{
    if (!k.hasOwnProperty(i)) {
        k[i] = 1
    }
}
)
arr2.map(j=>{
    if (!k.hasOwnProperty(j)) {
        k[j] = 1;
    } else {
        k[j] = 2;
    }
}
)
for (var i in k) {
    if (k[i] === 1)
        diff.push(+i)
}
return diff
}
getDiff([4, 3, 52, 3, 5, 67, 9, 3],[4, 5, 6, 75, 3, 334, 5, 5, 6])
于 2020-02-12T11:40:31.253 回答
3

如果你想找出两个对象数组之间的区别,你可以这样做:

let arrObj = [{id: 1},{id: 2},{id: 3}]
let arrObj2 = [{id: 1},{id: 3}]

let result = arrObj.filter(x => arrObj2.every(x2 => x2.id !== x.id))

console.log(result)

于 2021-05-26T09:30:31.373 回答
2

我一直在寻找一个不涉及使用不同库的简单答案,我想出了我自己的答案,我认为这里没有提到。我不知道它的效率如何,但它确实有效;

    function find_diff(arr1, arr2) {
      diff = [];
      joined = arr1.concat(arr2);
      for( i = 0; i <= joined.length; i++ ) {
        current = joined[i];
        if( joined.indexOf(current) == joined.lastIndexOf(current) ) {
          diff.push(current);
        }
      }
      return diff;
    }

对于我的代码,我也需要删除重复项,但我想这并不总是首选。

我想主要的缺点是它可能会比较许多已经被拒绝的选项。

于 2011-07-16T04:22:59.020 回答
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;
}

这将考虑当前类型的元素。b/c 当我们创建 a[a1[i]] 时,它将一个值从其原始值转换为字符串,因此我们丢失了实际值。

于 2012-04-18T06:43:40.293 回答
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);
于 2013-09-15T17:06:02.900 回答
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;
    }
}   
于 2014-01-30T17:19:27.443 回答
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);
    }
  }
}
于 2014-08-21T07:29:59.703 回答
2

只需比较所有值并返回具有不重复值的数组。

var main = [9, '$', 'x', 'r', 3, 'A', '#', 0, 1];

var arr0 = ['Z', 9, 'e', '$', 'r'];
var arr1 = ['x', 'r', 3, 'A', '#'];
var arr2 = ['m', '#', 'a', 0, 'r'];
var arr3 = ['$', 1, 'n', '!', 'A'];


Array.prototype.diff = function(arrays) {
    var items = [].concat.apply(this, arguments);
    var diff = [].slice.call(items), i, l, x, pos;

    // go through all items
    for (x = 0, i = 0, l = items.length; i < l; x = 0, i++) {
        // find all positions
        while ((pos = diff.indexOf(items[i])) > -1) {
            // remove item + increase found count
            diff.splice(pos, 1) && x++;
        }
        // if item was found just once, put it back
        if (x === 1) diff.push(items[i]);
    }
    // get all not duplicated items
    return diff;
};

main.diff(arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"

[].diff(main, arr0, arr1, arr2, arr3).join(''); // returns "Zeman!"
于 2015-10-11T07:23:28.667 回答
2
function diff(arr1, arr2) {
  var filteredArr1 = arr1.filter(function(ele) {
    return arr2.indexOf(ele) == -1;
  });

  var filteredArr2 = arr2.filter(function(ele) {
    return arr1.indexOf(ele) == -1;
  });
  return filteredArr1.concat(filteredArr2);
}

diff([1, "calf", 3, "piglet"], [1, "calf", 3, 4]); // Log ["piglet",4]
于 2016-02-08T06:57:50.667 回答
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;});
    };

此方法适用于复杂对象的数组。

于 2017-10-25T09:06:50.857 回答
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;
于 2018-12-16T19:45:42.330 回答
2

类似于 Ian Grainger 的解决方案(但在打字稿中):

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' ] 
// }
于 2019-06-12T21:01:18.357 回答
2

这是另一种可以返回差异的解决方案,就像 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}
于 2021-05-20T10:39:12.023 回答
2

尝试一下。

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

于 2021-05-24T05:41:02.520 回答
2

如果您有两个对象列表

const people = [{name: 'cesar', age: 23}]
const morePeople = [{name: 'cesar', age: 23}, {name: 'kevin', age: 26}, {name: 'pedro', age: 25}]

let result2 = morePeople.filter(person => people.every(person2 => !person2.name.includes(person.name)))
于 2021-10-15T09:01:22.133 回答
1

只是想......为了一个挑战;-)这会工作......(对于字符串,数字等的基本数组)没有嵌套数组

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

请注意,排序可能不会像上面提到的那样......但如果需要,请在数组上调用 .sort() 对其进行排序。

于 2009-07-27T11:11:13.810 回答
1

为了回应想要从另一个数组中减去一个数组的人......

如果不超过 1000 个元素,试试这个......

设置一个新变量来复制 Array01 并将其命名为 Array03。

现在,使用冒泡排序算法将 Array01 的元素与 Array02 进行比较,每当找到匹配项时,请对 Array03 执行以下操作...

 if (Array01[x]==Array02[y]) {Array03.splice(x,1);}

注意:我们正在修改 Array03 而不是 Array01,以免搞砸冒泡排序的嵌套循环!

最后,通过简单的赋值将 Array03 的内容复制到 Array01 中,就大功告成了。

于 2011-07-20T12:20:13.013 回答
1

Samuel:“对于我的代码,我也需要删除重复项,但我想这并不总是首选。我想主要的缺点是它可能会比较许多已经被拒绝的选项。”

当比较两个列表、数组等,并且元素少于 1000 时,3GL 世界的行业标准是使用避免上当的冒泡排序。

代码看起来像这样......(未经测试,但它应该可以工作)

var Array01=new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P');
var Array02=new Array('X','B','F','W','Z','X','J','P','P','O','E','N','Q');
var Array03=Array01;

for(x=1; x<Array02.length; x++) {
 for(y=0; y<Array01.length-1; y++) {
  if (Array01[y]==Array02[x]) {Array03.splice(y,1);}}}

Array01=Array03;

要测试输出...

for(y=0; y<Array01.length; y++) {document.write(Array01[y])}
于 2011-07-20T16:33:15.557 回答
1

如果不使用 hasOwnProperty 那么我们有不正确的元素。例如:

[1,2,3].diff([1,2]); //Return ["3", "remove", "diff"] This is the wrong version

我的版本:

Array.prototype.diff = function(array2)
  {
    var a = [],
        diff = [],
        array1 = this || [];

    for (var i = 0; i < array1.length; i++) {
      a[array1[i]] = true;
    }
    for (var i = 0; i < array2.length; i++) {
      if (a[array2[i]]) {
        delete a[array2[i]];
      } else {
        a[array2[i]] = true;
      }
    }

    for (var k in a) {
      if (!a.hasOwnProperty(k)){
        continue;
      }
      diff.push(k);
    }

    return diff;
  }
于 2013-05-29T10:25:40.320 回答
1

贡献我目前正在使用的 jQuery 解决方案:

if (!Array.prototype.diff) {
    Array.prototype.diff = function (a) {
        return $.grep(this, function (i) { return $.inArray(i, a) === -1; });
    }; 
}
于 2013-06-25T13:38:35.293 回答
1

CoffeeScript 版本:

diff = (val for val in array1 when val not in array2)
于 2015-03-20T16:33:54.577 回答
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' ]
于 2018-04-10T17:57:48.873 回答
1

我同意@luis-sieira 的解决方案

我为初学者创建了位自我解释功能,以便逐步轻松理解:

function difference(oneArr, twoArr){
  var newArr = [];
  newArr = oneArr.filter((item)=>{
      return !twoArr.includes(item)
  });
  console.log(newArr)
    let arr = twoArr.filter((item)=>{
        return !oneArr.includes(item)
     });
    newArr =  newArr.concat(arr);
  console.log(newArr)
}
difference([1, 2, 3, 5], [1, 2, 3, 4, 5])
于 2020-02-07T10:44:38.840 回答
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)));
    }
于 2021-01-16T15:44:47.767 回答
0

我在这里阅读的答案存在很多问题,这使得它们在实际编程应用程序中的价值有限。

首先,您将需要一种方法来控制数组中的两个项目“相等”的含义。如果您试图确定是否根据 ID 或类似的东西更新对象数组,则 === 比较不会减少它,坦率地说,这可能是您最可能想要的场景之一一个差异函数。它还将您限制在可以与 === 运算符进行比较的数组中,即字符串、整数等,这对于成年人来说几乎是不可接受的。

其次,diff 操作有三种状态结果:

  1. 在第一个数组中但不在第二个数组中的元素
  2. 两个数组共有的元素
  3. 在第二个数组中但不在第一个数组中的元素

我认为这意味着您需要不少于 2 个循环,但是如果有人知道将其减少到一个的方法,那么您可以使用肮脏的技巧。

这是我拼凑的东西,我想强调我绝对不在乎它在旧版本的 Microshaft 浏览器中不起作用。如果您在像 IE 这样的劣质编码环境中工作,则由您自己修改它以使其在您遇到的不令人满意的限制范围内工作。

Array.defaultValueComparison = function(a, b) {
    return (a === b);
};

Array.prototype.diff = function(arr, fnCompare) {

    // validate params

    if (!(arr instanceof Array))
        arr = [arr];

    fnCompare = fnCompare || Array.defaultValueComparison;

    var original = this, exists, storage, 
        result = { common: [], removed: [], inserted: [] };

    original.forEach(function(existingItem) {

        // Finds common elements and elements that 
        // do not exist in the original array

        exists = arr.some(function(newItem) {
            return fnCompare(existingItem, newItem);
        });

        storage = (exists) ? result.common : result.removed;
        storage.push(existingItem);

    });

    arr.forEach(function(newItem) {

        exists = original.some(function(existingItem) {
            return fnCompare(existingItem, newItem);
        });

        if (!exists)
            result.inserted.push(newItem);

    });

    return result;

};
于 2012-05-15T14:58:54.423 回答
0

这个问题很老,但仍然是javascript 数组减法的热门问题,所以我想添加我正在使用的解决方案。这适用于以下情况:

var a1 = [1,2,2,3]
var a2 = [1,2]
//result = [2,3]

以下方法将产生所需的结果:

function arrayDifference(minuend, subtrahend) {
  for (var i = 0; i < minuend.length; i++) {
    var j = subtrahend.indexOf(minuend[i])
    if (j != -1) {
      minuend.splice(i, 1);
      subtrahend.splice(j, 1);
    }
  }
  return minuend;
}

应该注意的是,该函数不包括减数中不存在于被减数中的值:

var a1 = [1,2,3]
var a2 = [2,3,4]
//result = [1]
于 2014-01-14T22:02:37.863 回答
0

只是修剪字符串以确保....空格不会影响差异

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].trim()]) delete a[a2[i].trim()];
    else a[a2[i].trim()]=true;
    for(var k in a)
        diff.push(k);
    return diff;
}
于 2014-03-07T19:09:56.337 回答
0

我已经尝试了以上所有这些方法,但是当您需要匹配而不接受重复项时,这些都不起作用。

例如:

var a1 = [1, 2, 1, 4], a2 = [1, 2, 4];

将返回一个空的 diff 数组,因为2将在第二个数组中找到一次,即使我们需要它匹配两次。

所以我设法解决了一些问题:

Array.prototype.diff = function(a) {
    return this.filter(function(item) {
        match = a.indexOf(item);
        if (match)
            a.splice(match, 1);
        return match < 0;
    });
};
于 2014-10-27T16:12:14.907 回答
0

这是我用来获取 2 个数组之间差异的函数 - 它适用于数字、字符串、混合 num/string 数组。不是数组/多维数组中的对象文字

function diff(arr1, arr2) {

    var x, 
        t;

    function uniq(a, b) {
        t = b;

        if( (b === 0 && x[b+1]!==a) || 
           (t > 0 && a !== x[b+1] && a !== x[b-1]) ) {
            return  a;
        }
    }


    x = arr1.concat(arr2).sort();

    return x.filter(uniq);
}

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

diff(a1, a2);
于 2014-12-14T02:26:20.913 回答
0

如果你的数组包含对象,那么如果你想比较一个属性就会变得有点困难。

幸运的是lodash,它很容易使用_containsand _.pluck

var list1 = [{id: 1},{id: 2}];
var list1 = [{id: 1},{id: 2}, {id: 3}];

//es6
var results = list2.filter(item => {
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//es5
var results = list2.filter(function(item){
  return !_.contains(_.pluck(list1, 'id'), item.id);
});

//results contains [{id: 3}]
于 2015-06-15T08:19:17.410 回答
0

这是我使用的:

var newArr = a1.filter(function(elem) {
            return a2.indexOf(elem) === -1;
        }).concat( a2.filter(function(elem) {
            return a1.indexOf(elem) === -1;
        }));
console.log(newArr);

或者这个

var newArr = a1.concat(a2);
        function check(item) {
            if (a1.indexOf(item) === -1 || a2.indexOf(item) === -1) {
                return item;
            }
        }
        return newArr.filter(check);
于 2016-01-16T15:05:18.397 回答
0
var arrayDifference = function(arr1, arr2){
  if(arr1 && arr1.length){
    if(arr2 && arr2.length > 0){
      for (var i=0, itemIndex; i<arr2.length; i++){
        itemIndex = arr1.indexOf(arr2[i]);
        if(itemIndex !== -1){
          arr1.splice(itemIndex, 1);
        }
      }
    }
    return arr1;
  }
  return [];
};

arrayDifference([1,2,3,4,5], [1,5,6]);
于 2016-05-24T07:33:49.163 回答
0

艰难的方式(如果您想做比 .indexOf 更花哨的事情)

var difference = function (source, target) {
    return source.reduce(function (diff, current) { 
        if (target.indexOf(current) === -1) { 
            diff.push(current); 
        }

        return diff; 
    }, []);
}

简单的方法

var difference = function (source, target) {
    return source.filter(function (current) {
        return target.indexOf(current) === -1;
    });
}
于 2016-09-06T14:43:14.037 回答
0

数据:

var new_storage = JSON.parse('[{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0006"}]');

var old_storage = JSON.parse('[{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0003"},{"id_order":"0004"},{"id_order":"0005"}]');

使用过滤器:

var diff = new_storage
.filter(x => {if(!(old_storage.filter(y => y.id_order==x.id_order)).length){return x}})
    .concat(old_storage
    .filter(x => {if(!(new_storage.filter(y => y.id_order==x.id_order)).length){return x}})
                       ) 

console.log(JSON.stringify(diff))

两个数组的结果差异

[{"id_order":"0006"},{"id_order":"0001"},{"id_order":"0002"},{"id_order":"0005"}]
于 2016-10-13T23:41:11.317 回答
0
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)));
}
于 2017-01-12T14:06:44.657 回答
0
function array_diff(a, b) {

    let array = [];
    for(let i = 0; i <a.length; i++) {
        let k = 0;
        for( let j = 0; j < b.length; j++) {
            if(a[i]!==b[j]) {
                k++;
            }
            if(k===b.length) {
                array = array.concat(a[i]);
            }
        }

        if(b.length ===0) {
            array = array.concat(a[i]);
        }
    }
    return array;
}
于 2017-06-02T20:54:05.087 回答
0

这是我获得两个数组差异的方法。纯净而干净。

它将返回一个包含 [添加列表] 和 [删除列表] 的对象。

  function getDiff(past, now) {
        let ret = { add: [], remove: [] };
        for (var i = 0; i < now.length; i++) {
          if (past.indexOf(now[i]) < 0)
            ret['add'].push(now[i]);
        }
        for (var i = 0; i < past.length; i++) {
          if (now.indexOf(past[i]) < 0)
            ret['remove'].push(past[i]);
        }
        return ret;
      }
于 2017-08-15T07:05:59.283 回答
0

您可以使用一个通用对象并计算第一个数组中每个值的频率。对于第二个数组,减少公共对象中的值。然后遍历所有键并添加值大于1的所有键。

const difference = (a1, a2) => {
  var obj = {};
  a1.forEach(v => obj[v] = (obj[v] || 0) + 1);
  a2.forEach(v => obj[v] = (obj[v] || 0) - 1);
  return Object
      .keys(obj)
      .reduce((r,k) => {
        if(obj[k] > 0)
          r = r.concat(Array.from({length: obj[k]}).fill(k));
        return r;
      },[]);
};
const result = difference(['a', 'a', 'b', 'c', 'd'], ['a', 'b']);
console.log(result);

于 2018-01-26T16:48:05.403 回答
0

**这将根据“类型”参数返回任意 2 个数组的唯一值数组、重复数组或非重复数组(差异)。**

let json1 = ['one', 'two']
let json2 = ['one', 'two', 'three', 'four']

function uniq_n_shit (arr1, arr2, type) {

  let concat = arr1.concat(arr2)
  let set = [...new Set(concat)]

  if (!type || type === 'uniq' || type === 'unique') {

    return set

  } else if (type === 'duplicate') {

    concat = arr1.concat(arr2)
    return concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

  } else if (type === 'not_duplicate') {

    let duplicates = concat.filter(function (obj, index, self) {
      return index !== self.indexOf(obj)
    })

    for (let r = 0; r < duplicates.length; r++) {
      let i = set.indexOf(duplicates[r]);
      if(i !== -1) {
        set.splice(i, 1);
      }
    }

    return set

  }
}

console.log(uniq_n_shit(json1, json2, null)) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'uniq')) // => [ 'one', 'two', 'three', 'four' ]
console.log(uniq_n_shit(json1, json2, 'duplicate')) // => [ 'one', 'two' ]
console.log(uniq_n_shit(json1, json2, 'not_duplicate')) // => [ 'three', 'four' ]
于 2018-06-08T07:31:00.737 回答
0

对我来说,将其作为部分功能处理起来感觉更容易。很惊讶没有看到函数式编程解决方案,这是我在 ES6 中的:

const arrayDiff = (a, b) => {
  return diff(b)(a);
}

const contains = (needle) => (array) => {
  for (let i=0; i < array.length; i++) {
    if (array[i] == needle) return true;
  }

  return false;
}

const diff = (compare) => {
    return (array) => array.filter((elem) => !contains(elem)(compare))
}
于 2018-12-15T15:49:26.070 回答
0

如果您不关心原始数组并且编辑它们没有问题,那么这是更快的算法:

let iterator = arrayA.values()
let result = []
for (entryA of iterator) {
    if (!arrayB.includes(entryA)) {
        result.push(entryA)
    } else {
        arrayB.splice(arrayB.indexOf(entryA), 1) 
    }
}

result.push(...arrayB)
return result

于 2019-07-30T11:57:54.670 回答
0

基于Thinker's answer,但允许重复。

映射在它们出现时递增映射值,如果它们在另一个数组中,则递减它们。

任何剩余的都将包含在差价中。

function diff(curr, prev) {
  let a = curr.split('').sort(), b = prev.split('').sort(), c = arrDiff(a, b);
  console.log(JSON.stringify(a), '-', JSON.stringify(b), '=', JSON.stringify(c));
  return c;
}

function arrDiff(larger, smaller) {
  var entries = {};
  for (var i = 0; i < larger.length; i++) {
    entries[larger[i]] = (entries[larger[i]] || 0) + 1;
  }
  for (var i = 0; i < smaller.length; i++) {
    if (entries[smaller[i]]) {
      entries[smaller[i]] -= 1;
    } else {
      entries[smaller[i]] = (entries[smaller[i]] || 0) + 1;
    }
  }
  return Object.keys(entries).sort().reduce((diff, key) => {
    if (entries[key] > 0) {
      for (var i = 0; i < entries[key]; i++) {
        diff.push(key);
      }
    }
    return diff;
  }, []);
}

// Smaller is a subset of Larger
console.log('Result:', JSON.stringify(diff('ENLIGHTEN', 'LENGTHEN'))); // [ I ]
console.log('Result:', JSON.stringify(diff('STRENGTH', 'TENTHS')));    // [ G, R ]

// Both have a unique value
console.log('Result:', JSON.stringify(diff('BUBBLE', 'RUBBLE')));      // [ B, R ]
.as-console-wrapper { top: 0; max-height: 100% !important; }

于 2019-12-17T13:57:19.193 回答
0

根据以前的答案......取决于您是否想要一个高效或“漂亮的 oneliner”解决方案。

一般有3种方法...

  • “手动迭代”(使用 indexOf) - 具有 O(n2) 复杂度的天真(慢)

    var array_diff_naive = function(a,b){
    
     var i, la = a.length, lb = b.length, res = [];
    
     if (!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;
    }
    
  • “抽象迭代”(使用过滤器和连接库方法) - 手动迭代的语法糖(看起来更好,仍然很烂)

    var array_diff_modern = function(a1,a2){
    
    
     return a1.filter(function(v) { return  !a2.includes(v); } )
         .concat(a2.filter(function(v) { return !a1.includes(v);}));
    }
    
  • “使用哈希表”(使用对象键) - 效率更高 - 仅 O(n),但输入数组值的范围略有限制

     var array_diff_hash = function(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;
    }
    

在 jsperf
https://jsperf.com/array-diff-algo上看到这个

于 2020-07-12T12:14:08.157 回答
0

这是一个稍作修改的版本,它使用 Object 来存储哈希值,可以处理数组中的数字和字符串。

function arrDiff(a, b) {
  const hash = {};
  a.forEach(n => { hash[n] = n; });
  b.forEach(n => {
    if (hash[n]) {
      delete hash[n];
    } else {
      hash[n] = n;
    }
  });
  return Object.values(hash);
}
于 2020-09-10T04:52:19.337 回答
0
var compare = array1.length > array2.length ? array1 : array2;
var compareWith = array1.length > array2.length ? array2 : array1;
var uniqueValues = compareWith.filter(function(value){
                    if(compare.indexOf(vakye) == -1)
                       return true;
                   });

这将检查哪一个是数组中较大的一个,然后进行比较。

于 2020-11-07T18:54:43.177 回答
0
function diffArray(newArr, oldArr) {
    var newSet = new Set(newArr)
    var diff = []
    oldArr.forEach((a) => {
        if(!newSet.delete(a))diff.push(a)
    })
    return diff.concat(Array.from(newSet)) 
}
于 2020-12-08T06:06:10.103 回答
0

回应adaen关闭的帖子(比较两个包含整数的数组 JavaScript):

几个选项:

  1. 最简单 -> 您可以将第二个数组的所有条目添加到哈希图中。然后遍历第一个数组中的条目并记录哈希图中不存在的条目。
const arrOne = [2,3,10,7,9,15,7,15,21,1];
const arrTwo = [3,15,1,2,21];

const hash = {};

arrTwo.forEach(a => hash[a]++);
arrOne.filter(a => typeof hash[a] === 'undefined').forEach(a => console.log(a));
  1. 您的另一个选择是对两个数组进行排序。然后遍历第二个数组。在其中,迭代第一个数组。当您遇到第一个数组中的条目小于第二个数组中的下一个条目但不等于它时,您将它们注销。
const arrOne = [2,3,10,7,9,15,7,15,21,1].sort((a,b)=>a-b);
const arrTwo = [3,15,1,2,21].sort((a,b)=>a-b);

var i1 = 0;
for(var i2 = 0; i2 < arrTwo.length; i2++) {
  while(arrOne[i1] < arrTwo[i2+1]) {
    if(arrOne[i1] != arrTwo[i2]) {
      console.log(arrOne[i1]);
    }
    i1++;
  }
}
于 2021-09-02T17:17:56.607 回答
-1

我陷入了这个问题,这是为了得到两个简单数组的区别

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

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

而且我不明白为什么不使用基本的 for 循环:

for(var i=0; i < a1.length; i++) {
  for(var j=0; j < a2.length; j++) {
    if(a1[i] == a2[j]) {
      a2.splice(j, 1);
    }
  }
}

这将返回所需的["c", "d"]

[编辑] 就在上面提出的,迟到了。

无论如何,有什么好的理由避免这个简单的解决方案?

于 2013-06-14T17:54:10.170 回答
-2

转换为字符串对象类型:

[1, 1].toString() === [1, 1].toString(); // true
于 2015-10-04T10:18:52.017 回答