javascript - 使用 JavaScript,如何获取两个对象数组之间的差异

  显示原文与译文双语对照的内容

我有两个这样的结果集:


//Result 1


[


 { value="0", display="Jamsheer" },


 { value="1", display="Muhammed" },


 { value="2", display="Ravi" },


 { value="3", display="Ajmal" },


 { value="4", display="Ryan" }


]



//Result 2


[


 { value="0", display="Jamsheer" },


 { value="1", display="Muhammed" },


 { value="2", display="Ravi" },


 { value="3", display="Ajmal" },


]




[{ value="4", display="Ryan" }]



在JavaScript中做类似这样的事情有可能?

时间:

使用本机 JS,类似这样的操作:


a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]


b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]



function comparer(otherArray){


 return function(current){


 return otherArray.filter(function(other){


 return other.value == current.value && other.display == current.display


 }).length == 0;


 }


}



var onlyInA = a.filter(comparer(b));


var onlyInB = b.filter(comparer(a));



result = onlyInA.concat(onlyInB);



console.log(result);

你可以使用 Array.prototype.filter()Array.prototype.some()

下面是一个( 假定数组存储在变量 result1result2 中) 示例:


//Find values that are in result1 but not in result2


var uniqueResultOne = result1.filter(function(obj) {


 return!result2.some(function(obj2) {


 return obj.value == obj2.value;


 });


});



//Find values that are in result2 but not in result1


var uniqueResultTwo = result2.filter(function(obj) {


 return!result1.some(function(obj2) {


 return obj.value == obj2.value;


 });


});



//Combine the two arrays of unique entries


var result = uniqueResultOne.concat(uniqueResultTwo);



我创建一个函数来接受谓词确定两个对象是否相等,并返回一个基于该谓词的对称差异的函数:


a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"}, { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]


b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]



var makeSymmDiffFunc = (function() {


 var contains = function(pred, a, list) {


 var idx = -1, len = list.length;


 while (++idx <len) {if (pred(a, list[idx])) {return true;}}


 return false;


 };


 var complement = function(pred, a, b) {


 return a.filter(function(elem) {return!contains(pred, elem, b);});


 };


 return function(pred) {


 return function(a, b) {


 return complement(pred, a, b).concat(complement(pred, b, a));


 };


 };


}());



var myDiff = makeSymmDiffFunc(function(x, y) {


 return x.value === y.value && x.display === y.display;


});



var result = myDiff(a, b);//=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}



相比于 cerebrus ( 与Kasper方法一样),它有一个较小的优势,因为它在早期转义,如果找到一个,它就不会检查列表的其他部分。 如果我有一个方便的咖喱功能,我会这样做有点不同,但这工作正常。

说明

注释要求对初学者进行更详细的解释。 这是一个尝试。

我们将以下函数传递给 makeSymmDiffFunc:


function(x, y) {


 return x.value === y.value && x.display === y.display;


}



这个函数是我们如何决定两个对象相等的。 像所有返回true或false的函数一样,它可以被称为"谓词函数",但这只是术语。 主要要点是 makeSymmDiffFunc 配置了一个函数,如果我们认为它们相等,则返回 true 并返回。

使用 makeSymmDiffFunc ( 读取"使对称差分函数") 返回一个新函数:


 return function(a, b) {


 return complement(pred, a, b).concat(complement(pred, b, a));


 };



这是我们实际使用的函数。 我们通过两个列表,它找到第一个不在第二个列表中的元素,然后在第二个列表中组合。

然而,我可以通过 some 重新查看一下代码,并使用简化主函数:


var makeSymmDiffFunc = (function() {


 var complement = function(pred, a, b) {


 return a.filter(function(x) {


 return!b.some(function(y) {return pred(x, y);});


 });


 };


 return function(pred) {


 return function(a, b) {


 return complement(pred, a, b).concat(complement(pred, b, a));


 };


 };


}());



complement 使用谓词并返回它的第一个列表的元素,而不是第二个列表中的元素。 这比我第一次使用单独的contains 函数要简单。

最后,在立即调用的function expression ( IIFE ) 中包装主函数,以将内部 complement 函数保留在全局范围之外。

更新,数年后

现在ES2015已经变得非常普遍,我建议使用相同的技术,具有较少的样板:


const diffBy = (pred) => (a, b) => a.filter(x =>!b.some(y => pred(x, y)))


const makeSymmDiffFunc = (pred) => (a, b) => diffBy(pred)(a, b).concat(diffBy(pred)(b, a))



const myDiff = makeSymmDiffFunc((x, y) => x.value === y.value && x.display === y.display)



const result = myDiff(a, b)


//=> {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}



...