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

Joh*_*wan 660 javascript arrays array-difference

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

例如:

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

// need ["c", "d"]
Run Code Online (Sandbox Code Playgroud)

任何建议都非常感谢.

Lui*_*ira 948

使用ES7有更好的方法:

路口

 let intersection = arr1.filter(x => arr2.includes(x));
Run Code Online (Sandbox Code Playgroud)

交点差异维恩图

因为[1,2,3] [2,3]它会屈服[2,3].另一方面,因为[1,2,3] [2,3,5]将返回同样的事情.

区别

let difference = arr1.filter(x => !arr2.includes(x));
Run Code Online (Sandbox Code Playgroud)

正确的差异维恩图

因为[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)));
Run Code Online (Sandbox Code Playgroud)

对称差异维恩图

这样,您将获得一个包含arr1的所有元素的数组,这些元素不在arr2中,反之亦然

正如@Joshaven Potter在答案中指出的那样,你可以将它添加到Array.prototype中,这样它就可以这样使用:

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

  • 我更喜欢检查`<0`而不是`== -1` (3认同)
  • 计算 `Array` 差异是所谓的 `set operation`,因为属性查找是 `Set` 自己的工作,它比 `indexOf`/`includes` 快几个数量级。简而言之,您的解决方案效率很低,而且速度很慢。 (3认同)
  • 是不是`Array.includes()`ES7功能而不是ES6?[(1)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)[(2)](https://www.ecma-international. org/ecma-262/7.0 /#sec-array.prototype.includes) - 并继续使用ES6你可以使用`Array.some()`例如`let intersection = aArray.filter(a => bArray.some( b => a === b))`,不是吗? (3认同)
  • @ftor,但是对于“Set”,值必须是唯一的,不是吗? (2认同)
  • @LuisSieira我知道它适用于`[1,2,3] [2,3,5]`,因为数字是唯一的,但如果你说`[1,1,2,3] [1,2 ,3,5]` 和预期的 `[1]` 你不能使用 `Set`。你的解决方案也行不通:-/我最终创建了[这个函数](http://pastebin.com/ceVJ92uz),因为我想不出一个更简洁的令人满意的方法。如果您对如何做到这一点有任何想法,我很想知道! (2认同)
  • 另请参阅[Nina Scholz 的回答](/sf/answers/3436601171/)。我尝试使用二分搜索而不是“includes”,这显然大大提高了速度(将复杂性从“O(n^2)”提高到“O(n log2 n)”)。使用她的小函数而不是二分搜索,速度提高了 2-3 倍,尤其是当数组几乎相同时。使用疯狂数组(100,000,000 个元素)时增加 10 倍以上... (2认同)

Jos*_*ter 896

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"]
Run Code Online (Sandbox Code Playgroud)

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"]
Run Code Online (Sandbox Code Playgroud)

注意 indexOf和filter在ie9之前不可用.

  • 如果你使用这样的函数:`[1,2,3] .diff([3,4,5])`它将返回`[1,2]`而不是`[1,2,4,5] `因此它无法解决原始问题中的问题,需要注意的事项. (71认同)
  • 唯一不支持filter和indexOf的浏览器是IE8.IE9确实支持它们.所以没错. (49认同)
  • 该解决方案具有O(n ^ 2)的运行时间,线性解决方案将更加有效. (42认同)
  • ie7和ie8仍然(不幸)非常相关,但是您可以在MDN站点上找到两个函数的polyfill代码:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter https:// developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf通过IE条件和BOOM加载"兼容性"下列出的代码.支持Ie7/8. (13认同)
  • @AlinPurcaru古代浏览器不支持!=错误.考虑到Netscape 2.0,这里的大多数JS代码都是"错误的".这是一个愚蠢的说法. (11认同)
  • 对我来说,最大的缺点是它修改了内置对象的原型.我宁愿避免这种情况. (8认同)
  • @jholloman:一个O(n*log(n))解决方案是对2个数组进行排序,然后进行线性合并.我们可以更好吗? (3认同)
  • @jholloman:是的,O(1)确实会更有效率! (3认同)
  • 你也可以使用jQuery提供的过滤功能. (2认同)
  • 请注意,此实现不适用于对象数组.有关更多信息,请参见http://stackoverflow.com/q/8672383/14731. (2认同)
  • 这只会找到左边数组 _has_ 右边数组 _does 没有的东西,反之亦然。因此,如果你调用 `[1,2,3,4,5,6].diff([3,4,5,10]);`,你的结果将是 `[1,2,6]`,而不是比预期的 `[1, 2, 6, 10]`。 (2认同)

sup*_*nic 305

到目前为止,这是使用jQuery获得您正在寻找的结果的最简单方法:

var diff = $(old_array).not(new_array).get();
Run Code Online (Sandbox Code Playgroud)

diff现在包含了old_array不存在的内容new_array

  • 这是一招吗?[doc](http://api.jquery.com/get/)将此方法视为[DOM元素方法]的一部分(http://api.jquery.com/category/miscellaneous/dom-element-methods /)而不是一般的数组助手.因此它现在可能以这种方式工作,但可能不会在未来的版本中,因为它不打算以这种方式使用它.虽然,如果它将成为一般的数组助手,我会很高兴. (8认同)
  • @Batman是的,但前提是它们是对_same_对象的引用(`{a:1}!= {a:1}`)([proof](http://jsfiddle.net/degq74y0/)) (4认同)
  • 这适用于数组中的对象吗? (2认同)
  • @robsch 当你对数组使用 `.not` 时,jQuery 使用它的内置实用程序 `.grep()`,专门用于过滤数组。我看不到这种变化。 (2认同)

Thi*_*ker 191

我假设你正在比较一个普通的数组.如果没有,则需要将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"));
Run Code Online (Sandbox Code Playgroud)

如果您不关心向后兼容性,更好的解决方案是使用过滤器.但是,这个解决方案仍然有效.

  • 这可能有效,但是它使用Array的过滤方法完成了在一行代码中可以完成的操作. (42认同)
  • 这不是最好的答案,但我正在给它一个慈善机构的投票,以帮助弥补不公平的downvotes.只有*错误的*答案才应该被低估,如果我正在研究一个范围广泛的浏览器项目(艰难时期发生),这个答案甚至可能会有所帮助. (23认同)
  • 这是错的!您正在使用JS数组作为关联数组. (8认同)
  • 为了清楚起见,这实现了_a1_和_a2_的_symmetric差异_,与此处发布的其他答案不同. (8认同)
  • 我可以知道当`var a1 = ['a','b'];`和`var a2 = ['a','b','c','d','b']时会发生什么. ,**它会返回错误的答案**,即`['c','d','b']`而不是`['c','d']`. (3认同)
  • 最快的方法是最明显天真的解决方案.我在这个帖子中测试了所有提出的对称差异解决方案,获胜者是:`函数diff2(a,b){var i,la = a.length,lb = b.length,res = []; if(!la)返回b; 否则如果(!lb)返回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; }` (3认同)

mah*_*off 152

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]
Run Code Online (Sandbox Code Playgroud)

与任何Underscore函数一样,您也可以使用更面向对象的样式:

_([1, 2, 3, 4, 5]).difference([5, 2, 10]);
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个性能良好的解决方案,尤其是当lodash和下划线继续争夺最佳实施时.此外,它与IE6兼容. (4认同)
  • 请注意,此实现不适用于对象数组.有关更多信息,请参见http://stackoverflow.com/q/8672383/14731. (4认同)
  • 如果参数顺序颠倒,请小心,它将不起作用。例如。_.difference( [5, 2, 10], [1, 2, 3, 4, 5]); 无法获得差异 (2认同)

Jo *_*iss 72

简单的JavaScript

"差异"有两种可能的解释.我会让你选择你想要的那个.说你有:

var a1 = ['a', 'b'     ];
var a2 = [     'b', 'c'];
Run Code Online (Sandbox Code Playgroud)
  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;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果你想获得['a', 'c'](包含了所有的元素或者 a1还是a2,但不能同时-所谓的对称差),使用此功能:

    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;
    }
    
    Run Code Online (Sandbox Code Playgroud)

Lodash/Underscore

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

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

ES6 Set,适用于非常大的阵列

上面的代码适用于所有浏览器.但是,对于超过10,000个项目的大型数组,它变得非常慢,因为它具有O(n²)复杂度.在许多现代浏览器中,我们可以利用ES6 Set对象来加快速度.Lodash Set会在可用时自动使用.如果您不使用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));
}
Run Code Online (Sandbox Code Playgroud)

笔记

如果您关心-0,+ 0,NaN或稀疏数组,所有示例的行为可能会令人惊讶或不明显.(对于大多数用途,这没关系.)

  • 感谢。你救了我的命。我必须比较 300K 阵列,并且您的“Set”解决方案工作得很好。这应该是公认的答案。 (3认同)

Sum*_*tra 63

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

var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
Run Code Online (Sandbox Code Playgroud)

区别

a2.filter(d => !a1.includes(d)) // gives ["c", "d"]
Run Code Online (Sandbox Code Playgroud)

路口

a2.filter(d => a1.includes(d)) // gives ["a", "b"]
Run Code Online (Sandbox Code Playgroud)

析取联合(对称差分)

[ ...a2.filter(d => !a1.includes(d)),
  ...a1.filter(d => !a2.includes(d)) ]
Run Code Online (Sandbox Code Playgroud)

  • @imrok我相信这就是你正在寻找的 [...a2.filter(d =&gt; !a1.includes(d)) , ...(a1.filter(d =&gt; !a2.includes(d)) )] (2认同)

Luc*_*one 47

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

在此输入图像描述


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));
    }));
}
Run Code Online (Sandbox Code Playgroud)

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);
    }));
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

例:

// 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"]
Run Code Online (Sandbox Code Playgroud)

对象数组之间的差异

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])
        );
    }));
}
Run Code Online (Sandbox Code Playgroud)

例:

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}]
Run Code Online (Sandbox Code Playgroud)


nki*_*tku 44

一内衬

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
));
Run Code Online (Sandbox Code Playgroud)

打字稿

游乐场链接

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 })
  );
Run Code Online (Sandbox Code Playgroud)


Sam*_*ijo 37

在这种情况下,您可以使用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}
Run Code Online (Sandbox Code Playgroud)

  • 这看起来像一个很好的图书馆!真遗憾你不能只需要下载`Set`功能而不必另外购买其他东西...... (4认同)
  • 哇,1年了?https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set (2认同)
  • @Loupax 不幸的是,内置的 ES Set 没有这个方便的 `difference` 方法。 (2认同)

pdb*_*ito 31

function diff(a1, a2) {
  return a1.concat(a2).filter(function(val, index, arr){
    return arr.indexOf(val) === arr.lastIndexOf(val);
  });
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我同意这是最干净,最简单的方法,并且它不需要触摸原型."如果你无法向一个六岁的孩子解释,你自己也不会理解." - 爱因斯坦 (3认同)

Al_*_*___ 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;
});
Run Code Online (Sandbox Code Playgroud)

它将返回['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;
});
Run Code Online (Sandbox Code Playgroud)


mae*_*ics 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']
Run Code Online (Sandbox Code Playgroud)


Sal*_*ali 12

随着ES6与套装和splat操作员的到来(在仅在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)))];
Run Code Online (Sandbox Code Playgroud)

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

  • @SalvadorDali `var difference = [...new Set([...a].filter(x =&gt; !b1.has(x)))];` 为什么要创建重复的 'a' 数组?为什么将过滤器的结果转换为集合,然后再转换回数组?这不等同于`var difference = a.filter(x =&gt; !b1.has(x));` (3认同)
  • @chovy,时间复杂度不同。我的解决方案是“O(n + m)”,您的解决方案是“O(n * m)”,其中 n 和 m 是数组的长度。如果列出很长的列表,我的解决方案将在几秒钟内运行,而您的解决方案将需要几个小时。 (2认同)
  • a.filter(x =&gt;!b1.has(x))更简单。请注意,该规范仅要求复杂度为n * f(m)+ m,而f(m)平均为次线性。它比`n * m`好,但不一定`n + m`。 (2认同)

小智 11

ES2015的功能方法

计算difference两个阵列之间的Set操作之一.该术语已经表明Set应该使用本机类型,以便提高查找速度.无论如何,当你计算两组之间的差异时,有三种排列:

[+left difference] [-intersection] [-right difference]
[-left difference] [-intersection] [+right difference]
[+left difference] [-intersection] [+right difference]
Run Code Online (Sandbox Code Playgroud)

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

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) );
Run Code Online (Sandbox Code Playgroud)

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) );
Run Code Online (Sandbox Code Playgroud)

我想这个例子是一个很好的起点,可以获得函数式编程意味着什么:

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


小智 10

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);
Run Code Online (Sandbox Code Playgroud)

这应输出: [ 1, 2, 6, 7 ]


Iur*_*kyi 9

另一种解决问题的方法

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]
Run Code Online (Sandbox Code Playgroud)


Vik*_*pta 8

如果你有两个对象列表

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)))
Run Code Online (Sandbox Code Playgroud)


riy*_* tk 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]
Run Code Online (Sandbox Code Playgroud)


Cat*_*Cat 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));
Run Code Online (Sandbox Code Playgroud)

所以这样你就可以做到array1.diff(array2)与众不同(虽然算法的时间复杂度很高 - 我相信O(array1.length x array2.length))


小智 6

function diffArray(arr1, arr2) {
  var newArr = arr1.concat(arr2);
  return newArr.filter(function(i){
    return newArr.indexOf(i) == newArr.lastIndexOf(i);
  });
}
Run Code Online (Sandbox Code Playgroud)

这对我有用


小智 6

使用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);
Run Code Online (Sandbox Code Playgroud)


小智 6

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

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

console.log(diffArr);
Run Code Online (Sandbox Code Playgroud)

输出:

[ 'c', 'd' ]
Run Code Online (Sandbox Code Playgroud)

  • 输出应该是 ['c', 'd'] 而不是 ['a', 'b'] (3认同)

KJ *_*han 5

要查找两个不重复的数组的差异:

function difference(arr1, arr2){

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

}
Run Code Online (Sandbox Code Playgroud)

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]

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

要查找两个不重复的数组的绝对差:

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

}
Run Code Online (Sandbox Code Playgroud)

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


Ali*_*nco 5

这是另一个可以返回差异的解决方案,就像 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 }), {})
  }
}
Run Code Online (Sandbox Code Playgroud)

这是一个用法示例:

arrDiff(['a', 'b', 'c'], ['a', 'd', 'c', 'f']) //{"b": false, "d": true, "f": true}
Run Code Online (Sandbox Code Playgroud)