尽管在思想上与@Cerbrus和@Kasper Moerch的方法相似,但我采用的是通用方法。我创建了一个接受谓词的函数,以确定两个对象是否相等(此处我们忽略该 $$hashKey
属性,但可以是任何东西),然后返回一个函数,该函数根据该谓词计算两个列表的对称差:
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 Moerch的方法)相比,它有一个较小的优势,那就是它可以尽早逃脱。如果找到匹配项,则无需检查列表的其余部分。如果我有一个curry
方便的函数,我会做一些不同的事情,但这很好用。
说明
评论要求为初学者提供更详细的解释。这是一个尝试。
我们将以下函数传递给makeSymmDiffFunc
:
function(x, y) {
return x.value === y.value && x.display === y.display;
}
此函数是我们确定两个对象相等的方式。像所有返回true
或的函数一样false
,它可以称为“谓词函数”,但这仅是术语。要点是makeSymmDiffFunc
配置了一个函数,该函数接受两个对象,true
如果认为它们相等,false
则返回,否则返回。
使用该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
函数要简单。
最后,将主函数包装在立即调用的函数表达式(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"}