3

I have a json string and I want to know what its maximum depth is. By depth I mean the number of embedded keys. So if one key as 7 "children" and know other key had that many, the depth would be 8.

Since the only types (I believe) that can embed other objects are arrays and other dictionaries that is all that would need to be checked. Is there a way to check this?

I was hoping to achieve this without external modules but if not I am targeting python3.

NOTE: Here is what I mean by "depth"

The following dictionary:

{
  "path": "/0001_Anthem",
  "name": "0001_Anthem",
  "isMovie": true,
  "runtime": 3600,
  "thumbnailLocation": "/thubs/test.png",
  "id": 1, 
  "media": [
    {
      "path": "/0001_Anthem/louvers.mp4",
      "name": "louvers.mp4"
    }
  ]
}

Would have a "depth" or length of 3 because the farthest embedded item is the key/value pair (level 3) in the media array (level 2), in the main dictionary (level 1). I am not sure what terminology others use, this is just the terminology I think make sense.

Thanks

4
  • 1
    Can you explain what you mean by depth in more detail? It doesn't sound like the usual definition. Maybe some examples? Commented Jun 19, 2015 at 1:07
  • Are you possibly pointing to collections.Mapping and collections.Sequence if you say "arrays and dicts"? Commented Jun 19, 2015 at 1:12
  • @Blorgbeard clarified Commented Jun 19, 2015 at 1:21
  • OK, that actually is the usual definition, I was just confused by your wording :) Commented Jun 19, 2015 at 1:33

4 Answers 4

13

Here's one implementation:

def depth(x):
    if type(x) is dict and x:
        return 1 + max(depth(x[a]) for a in x)
    if type(x) is list and x:
        return 1 + max(depth(a) for a in x)
    return 0
Sign up to request clarification or add additional context in comments.

2 Comments

Doesn't work test this {'children': [{'name': 'product service', 'children': [{'name': 'price', 'children': [{'name': 'cost', 'size': 8}]}, {'name': 'quality', 'children': [{'name': 'messaging', 'size': 4}]}]}, {'name': 'customer service', 'children': [{'name': 'Personnel', 'children': [{'name': 'CEO', 'size': 7}]}]}, {'name': 'product', 'children': [{'name': 'Apple', 'children': [{'name': 'iPhone 4', 'size': 10}]}]}]}
@jayprakashstar, could you please explain why is it that you think it doesn't work? According to @Startec's original question and definition, your example is depth 7. If you pretty-print your example, you'll see that the max indent level (all keys name and size) is precisely 7.
1
def depth(d):
    if hasattr(d, "values"):
        return 1 + max(map(depth, d.values()))
    if hasattr(d, "__len__") and not hasattr(d, "lower"):
        return 1 + max(map(depth, d))
    return 0

Comments

1

Taking a closer look at your Q, you want to get the depth from a JSON string. Here is a function I write:

# This function count list/dict/tuple as levels
def get_json_depth(s):
    d = {"(":")", "[":"]", "{":"}" }
    stack = []
    lefts = d.keys()
    rights = d.values()

    max_depth = 0
    depth = 0
    in_quotes = False

    for c in s:
            if c == '"':
                    in_quotes = not in_quotes
            if not in_quotes:
                    if c in lefts:
                            stack.append(c)
                            depth += 1
                            if depth > max_depth:
                                    max_depth = depth
                    elif c in rights:
                            if not stack:
                                    raise Exception()
                            if c != d[stack.pop()]:
                                    raise Exception()
    return max_depth

But if you don't mind using json.loads(s) to convert it to dictionary, then use @Blorgbeard's recursive function.

Comments

0

You can find the depth using a recursive function like so.

def depth(jsnFile):
    if jsnFile.has_key('children'):
       return 1 +  max([0] + map(depth, jsnFile['children']))
    else:
       return 1

1 Comment

I meant for a dictionary with unknown key names (where even the key names are not known)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.