python dynamic object query
<p>I have a python object structured like:</p>

<pre><code>tree = {
    "a": {
        "aa": {
            "aaa": {},
            "aab": {},
            "aac": {}
        },
        "ab": {
            "aba": {},
            "abb": {}
        }
    },
    "b": {
        "ba": {}
    },
    "c": {}
}
</code></pre>

<p>And a set of lists of strings like:</p>

<pre><code>arr_1 = ["a", "ab"]
arr_2 = ["b", "ab"]
arr_3 = ["a", "ab", "aba"]
</code></pre>

<p>Each list defines a path of keys in the tree and I want to determine whether the list describes a valid path through the tree or not.</p>

<p>Currently I can achieve a case by case answer like so:</p>

<pre><code>tree[arr_1[0]][arr_1[1]] # Returns correct object
tree[arr_2[0]][arr_2[1]] # Returns error
tree[arr_3[0]][arr_3[1]][arr_3[2]] # Returns correct object
</code></pre>

<p>Though this does not satisfy my requirements. I'd much prefer one function which will search the tree for the keys in any given list.</p>

<p>The following function is almost what I want but it does not handle lists of different lengths.</p>

<pre><code>def is_valid(tree, arr):
    obj = tree[arr[0]][arr[1]]
    if len(obj) &gt; 0:
        return(obj)
    else:
        return("No obj")
</code></pre>

<p>Currently this function outputs</p>

<pre><code>is_valid(tree, arr_1) # Returns the correct result
is_valid(tree, arr_2) # Returns an error
is_valid(tree, arr_3) # Returns the same result as arr_1, which is incorrect
</code></pre>

<p>Can anyone help me expand this function to react dynamicically to the length of the <code>arr</code> argument?</p>

<p>Thanks!</p>

<p>I think the easiest way to do this is to utilize recursion. Every sub-tree is a tree and every sub-path is a path, so we can look at whether or not the first element in the path is valid then continue on from there.</p>

<pre><code>def is_valid(tree, path):

    # base case. Any path would be valid for any tree
    if len(path) == 0:
        return True

    # the path must be invalid, no matter what comes before or after
    if not path[0] in tree:
        return False

    # look at the rest
    return is_valid(tree[path[0]], path[1:])
</code></pre>

<p>If you want the sub-tree a path describes you could instead do this:</p>

<pre><code>def is_valid(tree, path):

    if len(path) == 0:
        return tree # the only difference
    if not path[0] in tree:
        return False
    return is_valid(tree[path[0]], path[1:])
</code></pre>

python arrays object dictionary