How to check the depth of an object?

26,715

Solution 1

Well, here you go buddy, a function that does exactly what you need!

utils.depthOf = function(object) {
    var level = 1;
    for(var key in object) {
        if (!object.hasOwnProperty(key)) continue;

        if(typeof object[key] == 'object'){
            var depth = utils.depthOf(object[key]) + 1;
            level = Math.max(depth, level);
        }
    }
    return level;
}

A lot easier than we thought it would be. The issue was how it was incremented, it shouldn't have been recursively adding, rather getting the bottom-most and adding one, then choosing the max between two siblings.

Solution 2

This old question was recently resurrected and I don't see any answers as simple as this one (to be fair, this uses techniques not available when the question was written):

const objectDepth = (o) =>
  Object (o) === o ? 1 + Math .max (-1, ... Object .values(o) .map (objectDepth)) : 0

console .log (objectDepth ({foo: {bar: {baz: 'baa'}}}))
console .log (objectDepth ({abc: 'xyz'}))

This, like most answers here, will fail when the input object is cyclic. An answer that addresses that limitation would require much more sophistication.

Solution 3

Back from the dead! Throwing my solution into the mix -

function depth (t, mem = new Set)
{ if (mem.has(t))
    return Infinity
  else switch (mem.add(t), t?.constructor)
  { case Object:
    case Array:
      return 1 + Math.max
       ( -1
       , ...Object
           .values(t)
           .map(_ => depth(_, mem))
       )
    default:
      return 0
  }
}

console.log(depth({a: {b: {c: "z"}}}))   // 3
console.log(depth({a: "z"}))             // 1
console.log(depth({}))                   // 0
console.log(depth("z"))                  // 0
console.log(depth({a: [{b: "z"}]}))      // 3

const a = []
a[0] = a
console.log(depth(a))                    // Infinity

Share:
26,715

Related videos on Youtube

Kavi Siegel
Author by

Kavi Siegel

I'm a developer and general tinkerer/maker of awesome things. Robotics, web developer, renovation, I live for making stuff.

Updated on February 06, 2021

Comments

  • Kavi Siegel
    Kavi Siegel over 3 years

    I'm working on a permissions system with variable depth; depending on the complexity of a page, there could be more or less levels. I searched StackOverflow to find if this has been asked before, couldn't find it.

    If I have this object:

    {foo:{bar:{baz : 'baa'}}}
    

    I need it to return 3, it has 3 levels to it.

    With this object:

    {abc: 'xyz'} 
    

    It would have to be 1.

    This is what I have so far:

    utils.depthOf = function(object, level){
        // Returns an int of the deepest level of an object
        level = level || 1;
    
        var key;
        for(key in object){
            if (!object.hasOwnProperty(key)) continue;
    
            if(typeof object[key] == 'object'){
                level++;
                level = utils.depthOf(object[key], level);
            }
        }
    
        return level;
    }
    

    The problem is it counts sister elements too. It's actually not getting depth, it's counting all members of an object.

  • Umesh Patil
    Umesh Patil over 11 years
    What is the argument "level" in this function ?
  • Kavi Siegel
    Kavi Siegel over 11 years
    It would be called by saying utils.depthOf({}) - the second parameter is only used for recursion, which is why the second line is saying "level equals level if level isn't false, if level is false, level is one"
  • Kavi Siegel
    Kavi Siegel over 11 years
    That aside, this function doesn't actually work. If there are sister elements, it counts them as depth rather than "width." - I'm still working on that.
  • Umesh Patil
    Umesh Patil over 11 years
    +2 okay :) If I want to check dom dept of html element i.e. document. How do I call this function ?
  • Kavi Siegel
    Kavi Siegel over 11 years
    You'll run into a maximum call stack problem, most likely. The document object is really, really deep. That's literally a stack_overflow - but you would call it by just utils.depthOf(document)
  • nktssh
    nktssh over 8 years
    working wrong for situation {test: [{...}, {...}]}
  • Case
    Case over 4 years
    I know let and minify do not play friendly together.
  • zfrisch
    zfrisch about 4 years
    @nktssh that's because it's not doing a thorough enough job type checking. Arrays are objects. You would want to add another expression to the conditional using Array.isArray
  • Scott Sauyet
    Scott Sauyet about 4 years
    This would give a depth of 1 for {}, which presumably should be 0. Maybe return values .length ? 1 + Math .max ( /* ... */) : 0 ?
  • DonFuchs
    DonFuchs about 4 years
    My thought was that primitive values should have depth 0, thus {} depth 1 and so on, but that's just a matter of normalisation. Thing is, {} may be empty, but is has a depth, you can put something inside.
  • DonFuchs
    DonFuchs about 4 years
    And {} should have the same depth as {foo:"bar"}
  • Scott Sauyet
    Scott Sauyet about 4 years
    I guess it entirely depends on your notion of depth. This is a pretty old question and I don't know if the OP is still around, but my thought was that it was equivalent to the number of nodes in the longest path to a nested property.
  • Mulan
    Mulan over 3 years
    doesn't get much more simple than that!
  • Mulan
    Mulan over 3 years
    "here you go buddy" talking to yourself lmao
  • Scott Sauyet
    Scott Sauyet over 3 years
    Nice! I didn't try to do it, but simply assumed cyclic objects would be fairly difficult. This proves me entirely wrong.
  • Mulan
    Mulan over 3 years
    ha, i don't think i would've bothered to attempt it until reading your comment about it. it ended up being easier than i thought, too :D