获得两个数组之间的差异(包括重复)

时间:2016-10-01 19:26:33

标签: javascript arrays

我看到很多关于如何在javascript中获取数组的差异和对​​称差异的帖子,但我还没有找到关于如何找到差异的任何内容,包括重复。

例如:

let original = [1];
let updated = [1, 1, 2];

difference(updated, original);
// Expect: [1, 2]

有优雅的方法吗?我使用普通的javascript或lodash开放解决方案。

谢谢!

更新

为了澄清,应该支持无限数量的重复。另一个例子:

let original = [1, 1];
let updated = [1, 1, 1, 1, 1, 2];

difference(updated, original);
// Expect: [1, 1, 1, 2]

更新2

我意识到原始要求可能存在一些混淆。确实应该支持无限重复,但顺序不应该影响输出。

示例:

let original = [1, 1, 2];
let updated = [1, 2, 1, 1, 1];

difference(updated, original);
// Expect: [1, 1]

6 个答案:

答案 0 :(得分:2)

我建议使用这个解决方案,避免时间复杂度 O(n²)

function difference(a, b) {
    return [...b.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) - 1),
            a.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() ) 
    )].reduce( (acc, [v, count]) => acc.concat(Array(Math.abs(count)).fill(v)), [] );
}

let original = [1, 1];
let updated = [1, 1, 1, 1, 1, 2];
let res = difference(updated, original);

console.log(res);

解释

此解决方案为第一个数组的每个不同值( a )创建一个Map,其值为每个值的出现次数。然后以相同的方式将 b 添加到Map,除了出现次数为负数。如果该计数最终为零,那么当然这个密钥不应该在最终结果中结束。实际上,最终结果中出现的次数是每个键的Map中的计数的绝对值。

详细信息

代码以:

开头
new Map()

它是内部reduce的累加器的初始值。 reduce遍历 a 并更新Map中相应密钥的计数。因此reduce的最终结果是Map

然后,此Map成为外reduce的初始累加器值。 reduce遍历 b 并减少Map中的计数。

这个更新的Map通过spread运算符传播到一个数组中。该数组由2个元素的子数组组成,它们是键/值对。请注意,在这种情况下,值可以是正数,零或负数。

然后使用最终reduce迭代此数组。每个计数用于创建相应值的许多元​​素(绝对值)的数组。所有这些都连接到一个数组,作为函数的返回值。

后续问题

在评论中你解释说你实际上需要一些不同的东西,两个阵列的角色都不一样。应该返回第一个数组,但是从第二个数组中删除元素。

您可以使用此代码:

function difference2(a, b) {
    return a.filter(function(v) {
        return !this.get(v) || !this.set(v, this.get(v) - 1);
    }, b.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() ));
}

let original = [1, 1, 2];
let updated = [1, 1];
let res = difference2(original, updated);

console.log(res);

答案 1 :(得分:1)



function count(n,arr) {
  return arr.filter(a=>a==n).length
}

function diffBetween(arr,arr2) {
  diff = [];
  new Set(arr.concat(arr2)).forEach(
  a => {
    for(x=0;x<Math.abs(count(a,arr)-count(a,arr2));x++)
      diff.push(a)
    }
  );
  return diff;
}

console.log(diffBetween([1],[1,1,2]));
console.log(diffBetween([1,1],[1,1,1,1,1,2]));
console.log(diffBetween([1,1,3,4],[1,2,3]));
&#13;
&#13;
&#13;

这对你有什么用?

修改

&#13;
&#13;
function difference(a, b) { // trincot's code
    return [...b.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) - 1),
            a.reduce( (acc, v) => acc.set(v, (acc.get(v) || 0) + 1), new Map() ) 
    )].reduce( (acc, [v, count]) => acc.concat(Array(Math.abs(count)).fill(v)), [] );
}

function count(n,arr) { // My code
  return arr.filter(a=>a==n).length
}

function diffBetween(arr,arr2) { // My code
  diff = [];
  new Set(arr.concat(arr2)).forEach(
  a => {
    for(x=0;x<Math.abs(count(a,arr)-count(a,arr2));x++)
      diff.push(a)
    }
  );
  return diff;
}

in1 = [1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,2,2,2,2,2,2,2];
in2 = [1,2,3,4,5,6,1,2,3,4,5,6,7,1,1,1,1,1,1,2,2,2,2,2,2,2];

start = (new Date).getTime();
a = difference(in1,in2);
end = (new Date).getTime();
console.log("trincot done",end-start,"msec");
start = (new Date).getTime();
a = diffBetween(in1,in2);
end = (new Date).getTime();
console.log("stardust done",end-start,"msec");
&#13;
&#13;
&#13;

@ trincot上面的解决方案在我的测试中总是更快,所以他的数据集足够大,显然更优越。

答案 2 :(得分:1)

所以,我&#39; d:

  • 迭代更新后的数组,检查每个元素是否存在于原始数组中,如果它存在,我将其从原始数组中删除(注意:在下面的函数中我复制原始对象,所以我不会影响它,否则我将元素推送到差异数组。最后,我返回差异数组。

此代码适用于各种浏览器,因此我没有使用Array().indexOf和其他新的ECMAScript方法。

function difference(updated, original) {
  var i, l;
  /* copy original array */
  var degradation = [];
  for (var i = 0, ol = original.length; i < ol; ++i)
    degradation[i] = original[i]

  var diff = [];
  for (i = 0, l = Math.max(updated.length, ol); i < l; ++i) {
    var upd = updated[i];
    var index;
    var b, found;
    /* find updated item in degradation */
    for (b = 0, found = false; b < ol; ++b) {
      if (degradation[b] === upd) {
        /* remove item from degradation */
        delete degradation[b];
        found = true;
        break;
      }
    }
    if (!found)
      diff.push(upd);
  }
  return diff;
}

答案 3 :(得分:0)

    Array.prototype.Diff = function( secondArray ) {
    var mergedArray = this.concat( secondArray );
    var mergedString = mergedArray.toString();
    var finalArray = new Array();

    for( var i = 0; i < mergedArray.length; i++ ) {
        if(mergedString.match(mergedArray[i])) {
            finalArray.push(mergedArray[i]);
            mergedString = mergedString.replace(new RegExp(mergedArray[i], "g"), "");
        }
    }
    return finalArray;
}

var let = [ 1 ];
var updated = [ 1, 1, 2 ];

console.log(let.Diff(updated));

我喜欢原型方式。您可以将上面的原型函数保存在JS文件中,并导入到您想要的任何页面中,它可以用作对象的嵌入式函数(本例中为数组)。

答案 4 :(得分:0)

您可以执行以下操作;

var original = [1, 1, 1, 1, 2],
     updated = [1, 2, 1, 1, 3],
      result = (...a) => { var [shorter,longer] = [a[0],a[1]].sort((a,b) => a.length - b.length),
                                              s = shorter.slice();
                           return shorter.reduce((p,c) => { var fil = p.indexOf(c),
                                                                fis = s.indexOf(c);
                                                            fil !== -1 && (p.splice(fil,1),s.splice(fis,1));
                                                            return p;
                                                          },longer).concat(s);
                         };
console.log(result(updated,original));

答案 5 :(得分:0)

您可以执行以下步骤(O(n))。

让a和b是两个数组

步骤1.创建数组hash_map值的映射a作为键的键和出现次数。

步骤2.使用b推送result中不在a内的数组hash_map的所有元素。

步骤3.使用a推送result中不在b内的数组hash_map的所有元素。

这是完整的代码

function diff(a, b) {
    //Step 1 starts here
	var hash_map = a.reduce(function(map, key) {
		map[key] = map[key] ? (map[key]+1) : 1;
		return map;
	}, {});
    //Step 1 ends here
    //Step 2 starts here
	var result = b.filter(function(val) {
		if(hash_map[val]) {
			hash_map[val] = hash_map[val]-1;
			return false;
		}
		return true;
	});
    //Step 2 ends hers
    //Step 3 starts here
	Object.keys(hash_map).forEach(function(key) {
		while (hash_map[key]) {
			result.push(key);
			hash_map[key] = hash_map[key]-1;
		}
	});
    //Step 3 ends here
	return result;
}

console.log(diff([1],[1,1,2]));
console.log(diff([1,1,1],[1,1,1,1,1,2]));
console.log(diff([1,1,3,4],[1,2,3]));
console.log(diff([1,1,1,1,1,2], [1, 2, 1, 1, 3]));