对象比较:检查对象是否包含整个其他对象

时间:2014-04-13 17:06:26

标签: javascript

我有两个对象。他们的结构看起来有点像这样:

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

第二个:

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

}

您可能已经注意到,第二个物体包含整个第一个物体,以及第一个物体没有的物品。
如果第二个对象包含第一个对象的每个项目,我需要比较这两个对象并得到答案(true - false)。 true - 如果第一个对象的所有项目也在第二个对象中 false - 如果第一个对象的至少一个项目也不在第二个对象中,例如:如果第二个对象不具有" css"当然。

(第一个是要求,第二个是该人有什么。我需要检查此人是否满足所有要求)

可以是普通的JS,jQuery,等等。我不喜欢使用服务器端语言。

有没有办法做到这一点?

谢谢!

5 个答案:

答案 0 :(得分:3)

JavaScript(在ES5中)有两个复合本机类型(我假设您的代码中没有任何自定义集合,如果您这样做 - 我假设它们支持'旧'迭代协议(具有.length)< / p>

以下是解决方案的注释草图。我没有运行它 - 它可以帮助您了解如何实现此算法。请注意,这会为后引用(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
}

答案 1 :(得分:3)

只需递归检查:

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

对于更接近数组的类逻辑方法,无论顺序无关紧要,请添加类似

的内容
        a.sort();
        b = b.slice().sort()

(假设可订购的内容)在数组比较循环之前或用非常低效的

替换它
        return a.every(function(ael) {
            return b.some(function(bel) {
                return isContainedIn(ael, bel);
            });
        });

答案 2 :(得分:0)

编辑:没有注意到merge更改了第一个参数...更改了代码,但仍然会导致obj2更改。您可以添加_.cloneDeep(obj2)来处理这个问题,但到那时我的解决方案似乎并不优雅。同时使用cloneDeep更新了演示。

Edit2 :由于JSON.stringify要求对象属性的顺序在您比较的对象中相同,因此您可以使用Object comparison in JavaScript之类的内容。但是,在演示中,您可以看到它有效,所以我想很有可能对于您的情况,使用_.mergeJSON.stringify是可靠的。

使用lo-dash,您可以使用_.merge并检查结果是否与较大的对象相同。

function(obj1, obj2) {
    var obj3 =_.merge(_.cloneDeep(obj2), obj1);
    return JSON.stringify(obj3) === JSON.stringify(obj1);
}

demo

当然,另一种选择是用vanilla JS迭代整个对象。

答案 3 :(得分:0)

//当对象的顺序不相同时

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

答案 4 :(得分:0)

除了本杰明的答案-您还可以对此进行测试:

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
};

,甚至使用更清洁的解决方案: https://github.com/blackflux/object-deep-contain