Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript: Deep check objects have same keys

Question is similar to: How can I check that two objects have the same set of property names? but only one difference

I want to check:

var objOne = {"a":"one","b":"two","c":{"f":"three_one"}};
var objTwo = {"a":"four","b":"five","c":{"f":"six_one"}};

have the same set of keys in all level?

For example deepCheckObjKeys(objOne, objTwo) would return true where deepCheckObjKeys(objOne, objThree) return false, if:

var objThree = {"a":"four","b":"five","c":{"g":"six_one"}};

Since objThree.a.c.f is undefined in objThree.

A function like this:

'use strict';

function objectsHaveSameKeys() {
   for (var _len = arguments.length, objects = Array(_len), _key = 0; _key < _len; _key++) {
      objects[_key] = arguments[_key];
   }

   var allKeys = objects.reduce(function (keys, object) {
      return keys.concat(Object.keys(object));
   }, []);
   var union = new Set(allKeys);
   return objects.every(function (object) {
      return union.size === Object.keys(object).length;
   });
}

only checks the first level.

PS: objectsHaveSameKeys() ES6 equivalent:

function objectsHaveSameKeys(...objects):boolean {
   const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), []);
   const union = new Set(allKeys);
   return objects.every(object => union.size === Object.keys(object).length);
}
like image 212
Asim K T Avatar asked Jan 23 '17 08:01

Asim K T


People also ask

How do you know if two objects have the same key?

Approach: We will find keys of both objects by Object. keys(), which returns an array of keys of that object. For checking that every key in obj1 is also present in obj2, and if values of those key matches, we will use every() method.

Can objects have same keys JavaScript?

No, JavaScript objects cannot have duplicate keys. The keys must all be unique.

How do you check if objects are the same JavaScript?

equals function will determine if two objects are equal.

How do you check if an object contains a key in JavaScript?

There are mainly two methods to check the existence of a key in JavaScript Object. The first one is using “in operator” and the second one is using “hasOwnProperty() method”. Method 1: Using 'in' operator: The in operator returns a boolean value if the specified property is in the object.


2 Answers

I'd do a recursive check if a property's value is an object.

There's an interesting wrinkle here; actually, there are (at least) two:

  • What if one of the "objects" is null and the other has no properties? true or false?
  • What if one of the objects has {a: null} and the other has {a: 17}? true or false?
  • What if one of the objects has {a: null} and the other has {a: {}}? true or false?

For the purposes of this example, I've treated null like an object with no properties, but it's very much dependent on your use case. I can think of at least two other ways to go (null doesn't match anything but null, or null doesn't match anything but a non-object, even if the object has no own properties) and there are probably others.

See comments:

const deepSameKeys = (o1, o2) => {
    // Both nulls = same
    if (o1 === null && o2 === null) {
        return true;
    }

    // Get the keys of each object
    const o1keys = o1 === null ? new Set() : new Set(Object.keys(o1));
    const o2keys = o2 === null ? new Set() : new Set(Object.keys(o2));
    if (o1keys.size !== o2keys.size) {
        // Different number of own properties = not the same
        return false;
    }

    // Look for differences, recursing as necessary
    for (const key of o1keys) {
        if (!o2keys.has(key)) {
            // Different keys
            return false;
        }
        
        // Get the values and their types
        const v1 = o1[key];
        const v2 = o2[key];
        const t1 = typeof v1;
        const t2 = typeof v2;
        if (t1 === "object") {
            if (t2 === "object" && !deepSameKeys(v1, v2)) {
                return false;
            }
        } else if (t2 === "object") {
            // We know `v1` isn't an object
            return false;
        }
    }

    // No differences found
    return true;
};

// Checking your example
const objOne   = {"a": "one",  "b": "two",  "c": {"f": "three_one"}};
const objTwo   = {"a": "four", "b": "five", "c": {"f": "six_one"}};
const objThree = {"a": "four", "b": "five", "c": {"g": "six_one"}};

console.log("objOne vs. objTwo:         ", deepSameKeys(objOne, objTwo));        // true
console.log("objTwo vs. objThree:       ", deepSameKeys(objTwo, objThree));      // false

// `null` checks
console.log("{a: null} vs. {a: 17}      ", deepSameKeys({a: null}, {a: 17}));    // true
console.log("{a: null} vs. {a: {}}      ", deepSameKeys({a: null}, {a: {}}));    // true -- depending on your use case, you may want this to be false
console.log("{a: null} vs. {a: {x:1}}   ", deepSameKeys({a: null}, {a: {x:1}})); // false

// Differing value type check
console.log("{a: 1} vs. {a: '1'}}       ", deepSameKeys({a: 1}, {a: '1'}));      // true
like image 98
T.J. Crowder Avatar answered Oct 26 '22 12:10

T.J. Crowder


I guess you're looking for a deep-check version of the function provided [here] :)(How can I check that two objects have the same set of property names?).

Below is my attempt. Please note:

  • Solution does not check for null and is not bullet proof
  • I haven't performance tested it. Maybe the OP or anyone else can do that and share for the community.
  • I'm not a JS expert :).
function objectsHaveSameKeys(...objects) {
  const allKeys = objects.reduce((keys, object) => keys.concat(Object.keys(object)), [])
  const union = new Set(allKeys)
  if (union.size === 0) return true
  if (!objects.every((object) => union.size === Object.keys(object).length)) return false

  for (let key of union.keys()) {
    let res = objects.map((o) => (typeof o[key] === 'object' ? o[key] : {}))
    if (!objectsHaveSameKeys(...res)) return false
  }
  return true
}
like image 45
farqis Avatar answered Oct 26 '22 12:10

farqis