Python iterating through nested dictionaries

拈花ヽ惹草 提交于 2019-12-11 11:16:04

问题


First of all, here is the question and the code written:

def family_lineage(familytree, lineage):
    '''(dict, list of strs) -> boolean
    Return True if lineage specifies a list of names who are directly related
    in a chain of parent-child relationships, and NOT child-parent, parent-grandchild..etc,
    beginning from the first generation listed.

    >>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
                           'Li': {}},
                   'Guy': {}},
                      ['Gina'])
    True

    >>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
                               'Li': {}},
                       'Guy': {}},
                      ['Gina', 'Sam', 'Tina'])
    True
    >>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
                               'Li': {}},
                       'Guy': {}},
                      ['Gina', 'Tina'])
    False
    '''

So, in the above example, it shows the 'Guy' has no children, and 'Gina' has two children, 'Sam', and 'Li'. 'Sam' has one child, 'Tina'.

for k, v in familytree.items():
    for n, m in v.items():
        if lineage[0] == any(k) and len(lineage) == 1:
            return True
        elif lineage[0] == k and lineage[1] == n and len(lineage) ==2:
            return True
        elif lineage[0] == k and lineage[1] == n and lineage[2] == m and \
        len(lineage) == 3:
            return True
        else:
            return False

So, my question is, how would I write this if the familytree extended beyond three generations? Is there a more concise way of writing this code?


回答1:


Here is an iterative approach that will work even if lineage does not start at the top of the family tree:

def family_lineage(familytree, lineage):
    trees = [familytree]
    while trees:
        tree = trees.pop()
        trees.extend(t for t in tree.values() if t)
        for name in lineage:
            if name not in tree:
                break
            tree = tree[name]
        else:
            return True
    return False



回答2:


Basically, you want to see if you can traverse the tree; use reduce() to loop over the elements and if a KeyError is raised, the path doesn't exist:

def family_lineage(familytree, lineage):
    if not familytree:
        return False
    try:
        reduce(lambda d, k: d[k], lineage, familytree)
        return True
    except KeyError:
        # No match at this level, recurse down the family tree
        return any(family_lineage(val, lineage) for val in familytree.itervalues())

reduce() applies the lambda function recursively to lineage, starting with familytree.

To support finding lineages deeper down the tree, you need to recurse down the tree on KeyErrors.

Demo:

>>> tree = {'Gina': {'Sam': {'Tina': {}}, 'Li': {}}, 'Guy': {}}
>>> family_lineage(tree, ['Gina'])
True
>>> family_lineage(tree, ['Gina', 'Sam', 'Tina'])
True
>>> family_lineage(tree, ['Gina', 'Tina'])
False
>>> family_lineage(tree, ['Sam', 'Tina'])
True


来源:https://stackoverflow.com/questions/17797489/python-iterating-through-nested-dictionaries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!