Object Comparing: Check If An Object Contains The Whole Other Object
Solution 1:
Just recursively check it:
functionisContainedIn(a, b) {
if (typeof a != typeof b)
returnfalse;
if (Array.isArray(a) && Array.isArray(b)) {
// assuming same order at leastfor (var i=0, j=0, la=a.length, lb=b.length; i<la && j<lb;j++)
if (isContainedIn(a[i], b[j]))
i++;
return i==la;
} elseif (Object(a) === a) {
for (var p in a)
if (!(p in b && isContainedIn(a[p], b[p])))
returnfalse;
returntrue;
} elsereturn a === b;
}
> isContainedIn(requirements, person)
true
For a more set-logic-like approach to arrays, where order does not matter, add something like
a.sort();
b = b.slice().sort()
(assuming orderable contents) before the array comparison loop or replace that by the quite inefficient
return a.every(function(ael) {
return b.some(function(bel) {
returnisContainedIn(ael, bel);
});
});
Solution 2:
JavaScript (in ES5) has two composite native types (I'm assuming you don't have any custom collections in your code, if you do - I assume they support the 'old' iteration protocol (having .length)
Here is an annotated sketch of a solution. I did not run this - it's there to get you an idea of how to implement this algorithm. Note that this enters an endless loop for back references (var a = {}; a.a =a}
).
function sub(big,small){
if(typeof big === "function") return small === big; // function reference equality.if(big.length){ // iterable, for example array, nodelist etc. (even string!)if(small.length > big.length) returnfalse; // small is bigger!for(var i = 0; i < small.length; i++ ){
if(!sub(big[i],small[i])){ // doesn't have a propertyreturnfalse;
}
}
returntrue; // all properties are subproperties recursively
}
if(typeof big === "object" && big !== null){
// I assume null is not a subset of an object, you may change this, it's conceptualif(typeof small !== "object" || small === null) returnfalse;
for(var key in small){
// I consider the prototype a part of the object, you may filter this with a // hasOwnProperty check here.if(!sub(big[key],small[key])){ // doesn't have a propertyreturnfalse;
}
returntrue;
}
}
return big === small; // primitive value type equality// , or ES7 value type equality, future compat ftw :P
}
Solution 3:
Edit: didn't notice that merge
changes the first argument... changed the code, but it still would cause obj2 to change. You can add _.cloneDeep(obj2)
which should take care of that, but by then my solution doesn't seem as elegant. Updated the demo with cloneDeep
as well.
Edit2: Since JSON.stringify
requires the order of object properties to be the same in the objects you compare, you could instead use something like Object comparison in JavaScript. However, in the demo you can see that it works, so I would say there is a good chance that for your case, using _.merge
with JSON.stringify
is reliable.
With lo-dash, you can use _.merge
and check whether the result is the same as the larger object.
function(obj1, obj2) {
var obj3 =_.merge(_.cloneDeep(obj2), obj1);
returnJSON.stringify(obj3) === JSON.stringify(obj1);
}
Of course, another option would be to iterate over the entire object with vanilla JS.
Solution 4:
// When order of objects is not same
function isContainedIn(a, b) {
if (typeof a != typeof b)
returnfalse;
if (Array.isArray(a) && Array.isArray(b)) {
if(a.length == 1) {
var j=0;
while (j < b.length) {
if ((isContainedIn( a[0], b[j]))) {
returntrue;
}
j++;
}
returnfalse;
} else {
var k=0;
while (k < a.length) {
if (!(isContainedIn([a[k]], b))) {
returnfalse;
}
k++;
}
returntrue;
}
} elseif (Object(a) === a) {
for (var p in a)
if (!(p in b && isContainedIn(a[p], b[p])))
returnfalse;
returntrue;
} elsereturn a === b;
};
isContainedIn(requirements, person)
true
Solution 5:
In addition to Benjamin's answer - you could test this:
const sub = (big, small) => {
if (typeof big === 'function' || typeof small === 'string') return small === big; // function or string reference equalityif (big && big.length) { // iterable, for example array, nodelist etc. (even string!)if (small.length > big.length) returnfalse; // small is bigger!for (let i = 0; i < small.length; i++)
if (!sub(big[i], small[i])) // doesn't have a propertyreturnfalse;
returntrue; // all properties are subproperties recursively
}
if (typeof big === 'object' && big !== null) {
// I assume null is not a subset of an object, you may change this, it's conceptualif (typeof small !== 'object' || small === null) returnfalse;
// console.log(Object.keys(small));for (const key of Object.keys(small)) {
// I consider the prototype a part of the object, you may filter this with a// hasOwnProperty check here.if (sub(big[key], small[key]) === false) // doesn't have a propertyreturnfalse;
continue;
}
returntrue;
}
return big === small; // primitive value type equality
};
or even use a much cleaner solution: https://github.com/blackflux/object-deep-contain
Post a Comment for "Object Comparing: Check If An Object Contains The Whole Other Object"