我看到很多关于如何在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]
答案 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;
这对你有什么用?
修改强>
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;
@ 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]));