JavaScript中两个对象数组之间的区别
我有两个这样的结果集;
// Result 1 [ { 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" } ] // Result 2 [ { 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" } ]
我需要的最终结果是这些数组之间的差异,即最终的结果是这样的
[{ value="a63a6f77-c637-454e-abf2-dfb9b543af6c", 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()
结合使用。
这是一个例子(假设你的数组存储在variablesresult1
和result2
):
//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);
我采取了一个稍微更通用的方法,尽pipe类似于@Cerbrus和@Kasper Moerch的方法 。 我创build了一个函数,接受一个谓词来确定两个对象是否相等(这里我们忽略$$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的方法)相比有一个小小的优势,因为它早早地逃脱了; 如果find一个匹配,它不会检查列表的其余部分。 如果我有一个curry
function,我会做一点不同,但这工作正常。
说明
一个评论要求为初学者提供更详细的解释。 这是一个尝试。
我们通过下面的函数makeSymmDiffFunc
:
function(x, y) { return x.value === y.value && x.display === y.display; }
这个函数是我们如何决定两个对象是相等的。 像所有返回true
或false
函数一样,它可以被称为“谓词函数”,但这只是术语。 主要的一点是, makeSymmDiffFunc
configuration了一个接受两个对象的函数,如果我们认为它们是相等的,则返回true
否则返回false
。
使用这个, makeSymmDiffFunc
(读取“make symmetric difference function”)给我们一个新的函数:
return function(a, b) { return complement(pred, a, b).concat(complement(pred, b, a)); };
这是我们实际使用的function。 我们通过它两个列表,它在第一个不在第二个,然后在第二个不在第一个,并结合这两个列表中的元素。
但是,再次查看一下,我可以肯定地从你的代码中得到一个提示,并通过使用some
简化了主要function:
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
函数更简单。
最后,主函数被包装在一个立即调用的函数expression式( IIFE )中,以保持内部complement
函数不在全局范围内。
我做了一个比较两个任何types的对象,可以运行一个修改处理程序gist.github.com/bortunac“diff.js”的一个普遍的比较使用:
old_obj={a:1,b:2,c:[1,2]} now_obj={a:2 , c:[1,3,5],d:55}
所以属性a被修改,b被删除,c被修改,d被添加
var handler=function(type,pointer){ console.log(type,pointer,this.old.point(pointer)," | ",this.now.point(pointer));
}
现在使用像
df=new diff(); df.analize(now_obj,old_obj); df.react(handler);
控制台将显示
mdf ["a"] 1 | 2 mdf ["c", "1"] 2 | 3 add ["c", "2"] undefined | 5 add ["d"] undefined | 55 del ["b"] 2 | undefined
我认为@Cerbrus的解决scheme是现货。 我已经实现了相同的解决scheme,但是将重复的代码提取到它自己的函数(DRY)中。
function filterByDifference(array1, array2, compareField) { var onlyInA = differenceInFirstArray(array1, array2, compareField); var onlyInb = differenceInFirstArray(array2, array1, compareField); return onlyInA.concat(onlyInb); } function differenceInFirstArray(array1, array2, compareField) { return array1.filter(function (current) { return array2.filter(function (current_b) { return current_b[compareField] === current[compareField]; }).length == 0; }); }
import differenceBy from 'lodash/differenceBy' const myDifferences = differenceBy(Result1, Result2, 'value')
这将返回两个对象数组之间的差异,使用键值来比较它们。 注意两个具有相同值的东西不会被返回,因为其他键被忽略。
这是lodash的一部分。
如果您愿意使用外部库,则可以使用underscore.js中的_.difference来实现此目的。 _.difference返回数组中不存在的值。
_.difference([1,2,3,4,5][1,4,10]) ==>[2,3,5]