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

例如:

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

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

当前回答

简单地比较所有值,并返回数组与不重复的值。

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

其他回答

对我来说,把它作为部分函数处理比较容易。很惊讶没有看到函数式编程的解决方案,这是我在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))
}
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;
}

根据之前的答案…取决于你是想要一个高效的还是“漂亮的联机”解决方案。

一般有三种方法……

"manual iterative" (using indexOf) - naive with O(n2) complexity (slow) 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; } "abstract iterative" (using filter and concat library methods) - syntactic sugar for manual iterative (looks nicer, still sucks) 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);})); } "using hashtable" (using object keys) - much more efficient - only O(n), but has slightly limited range of input array values 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

一个衬垫

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

打印稿

操场上的链接

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

对于想要从一个数组中减去另一个数组的人的回应…

如果不超过1000个元素试试这个…

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

现在,使用冒泡排序算法比较Array01和Array02的元素,并在找到匹配时进行比较 对Array03执行以下操作…

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

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

最后,用一个简单的赋值操作将Array03的内容复制到Array01,就完成了。