【问题标题】:Python iterating through nested dictionariesPython遍历嵌套字典
【发布时间】:2013-07-21 18:33:22
【问题描述】:

首先,这是问题和编写的代码:

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
    '''

因此,在上面的示例中,它显示“Guy”没有孩子,“Gina”有两个孩子,“Sam”和“Li”。 “山姆”有一个孩子,“蒂娜”。

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

所以,我的问题是,如果家谱超过三代,我将如何写这个?有没有更简洁的方式来编写这段代码?

【问题讨论】:

标签: python dictionary nested nested-loops


【解决方案1】:

基本上,你想看看你是否可以遍历树;使用reduce() 循环遍历元素,如果引发KeyError,则路径不存在:

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()lambda 函数递归应用于lineage,从familytree 开始。

为了支持在树的更深处查找谱系,您需要在 KeyErrors 上沿树向下递归。

演示:

>>> 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

【讨论】:

  • 感谢您的帮助! :D
【解决方案2】:

即使lineage 不是从家族树的顶部开始,这里也是一种迭代方法:

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

【讨论】:

  • 使用队列的好方法。
  • 非常感谢您的帮助! :)
  • 你能解释一下你做了什么吗?将 familytree 放在方括号中,然后再使用 pop 的目的是什么?而当代码中断的时候,是不是直接去返回False呢?
  • trees 是树中所有未访问分支的容器,因此trees = [familytree] 只是为我们提供了整个树的起点。在 while 循环的每次迭代中,trees.pop() 将为我们提供树的一个分支(节点)以供使用,并且该节点的所有非空子节点都将添加到 trees。当代码中断时,它不会直接返回 False,它只是跳出 for 循环。 for 上的 else 子句仅在没有 break 时才执行,因此只有在找到 lineage 中的每个名称时才返回 True。当所有分支都被访问时,我们返回 False。
猜你喜欢
  • 2017-07-25
  • 2015-06-03
  • 1970-01-01
相关资源
最近更新 更多