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

前端 未结 5 668
日久生厌
日久生厌 2021-01-18 19:51

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

{
 education: [\"school\", \"institute\"],
 courses: [\"HTML\", \"JS\", \"CSS\"],
 Computer: {
            


        
相关标签:
5条回答
  • 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);
                });
            });
    
    0 讨论(0)
  • 2021-01-18 20:12

    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 equality
        if (big && big.length) { // iterable, for example array, nodelist etc. (even string!)
            if (small.length > big.length) return false; // small is bigger!
            for (let 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;
            // 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 property
                    return false;
                continue;
            }
            return true;
        }
        return big === small; // primitive value type equality
    };
    

    or even use a much cleaner solution: https://github.com/blackflux/object-deep-contain

    0 讨论(0)
  • 2021-01-18 20:15

    // When order of objects is not same

    function isContainedIn(a, b) {
        if (typeof a != typeof b)
            return false;
        if (Array.isArray(a) && Array.isArray(b)) {
            if(a.length == 1) {
                var j=0;
                while (j < b.length) {
                    if ((isContainedIn( a[0], b[j]))) {
                        return true;
                    }
                    j++;
                }
                return false;
            } else {
                var k=0;
                while (k < a.length) {
                    if (!(isContainedIn([a[k]], b))) {
                        return false;
                    }
                    k++;
                }
                return true;
            }
        } 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
    
    0 讨论(0)
  • 2021-01-18 20:16

    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
    }
    
    0 讨论(0)
  • 2021-01-18 20:27

    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);
        return JSON.stringify(obj3) === JSON.stringify(obj1);
    }
    

    demo

    Of course, another option would be to iterate over the entire object with vanilla JS.

    0 讨论(0)
提交回复
热议问题