Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object Comparing: check if an object contains the whole other object

Tags:

javascript

I have two objects. Their structure looks a bit like this:

{
 education: ["school", "institute"],
 courses: ["HTML", "JS", "CSS"],
 Computer: {
        "OS":"WXP",
        "WS":"NotePad"
         }
 }

The second:

{
 education: ["school", "university", "institute", "collage"],
 courses: ["HTML", "CSS", "JS", "Managing", "Directing"],
 Computer: {
        "OS":"WXP",
        "WS":"NotePad",
        "AV":"Avast"
         },
 something: function(){...},
 other: "thing"

}

As you may noticed, the second object containes the whole first object, plus some items that the first one doesn't have.
I need to compare these two objects, and get an answer(true-false) if the second objects containes every single item of the first object.
true - if all of the items of the first object are also in the second one
false - if at least one of the items of the first object is not also in the second one, for example: if the second object wouldn't have the "css" course.

(The first one is requirements, the second is what the person has. I need to check if the person has all of the requirements)

Could be plain JS, jQuery, whatever. I prefer not to use server-side languages for that.

is there a way of doing that?

THANKS!

like image 255
Reuven Karasik Avatar asked Apr 13 '14 17:04

Reuven Karasik


2 Answers

Just recursively check it:

function isContainedIn(a, b) {
    if (typeof a != typeof b)
        return false;
    if (Array.isArray(a) && Array.isArray(b)) {
        // assuming same order at least
        for (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;
    } else if (Object(a) === a) {
        for (var p in a)
            if (!(p in b && isContainedIn(a[p], b[p])))
                return false;
        return true;
    } else
        return 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) {
                return isContainedIn(ael, bel);
            });
        });
like image 93
Bergi Avatar answered Oct 11 '22 13:10

Bergi


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) return false; // small is bigger!
        for(var i = 0; i < small.length; i++ ){
            if(!sub(big[i],small[i])){ // doesn't have a property
                return false;
            }
        }
        return true; // 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 conceptual
        if(typeof small !== "object" || small === null) return false; 
        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 property
                 return false;
            }
            return true;
        }
    }
    return big === small; // primitive value type equality
                          // , or ES7 value type equality, future compat ftw :P
}
like image 20
Benjamin Gruenbaum Avatar answered Oct 11 '22 15:10

Benjamin Gruenbaum