【问题标题】:Generate all leaf-to-root paths in a dictionary tree in Python在 Python 中的字典树中生成所有从叶到根的路径
【发布时间】:2012-07-19 22:54:20
【问题描述】:

我有一个像这样的“非标准”形式的字典树:

tree = {'0': {'A': {'B': {'C': {}}}},
             {'D': {'E': {}},
                   {'F': {}}}}

叶节点被定义为字典键值对,其中的值是一个空字典。 我想将所有叶到根路径提取为列表列表,如下所示:

paths_ = [['C', 'B', 'A', '0'],
          ['E', 'D', '0'],
          ['F', 'D', '0']]

如果有帮助,路径也可以颠倒。

paths_ = [['0', 'A', 'B', 'C'],
          ['0', 'D', 'E'],
          ['0', 'D', 'F']]

我知道我必须递归地执行此操作,并且我需要每个路径的累加器列表。如果函数产生路径列表也很好。我到目前为止是这样的:

def paths(node, subtree, acc=[]):
    if not subtree:
        yield [node]+acc
    for n, s in subtree.items():
        yield paths(n, s, acc)

它并没有真正做到我想要的:

paths_ = list(paths('0', tree['0']))

理想情况下,这应该返回列表列表。任何帮助将不胜感激。

【问题讨论】:

  • 你能修复tree吗?它是无效的。

标签: python recursion tree


【解决方案1】:

假设您实际上打算为tree 使用以下结构:

tree = {'0': {'A': {'B': {'C': {}}},
              'D': {'E': {},
                    'F': {}}}}

这是一个类似的 paths() 函数,应该可以满足您的需求:

def paths(tree, cur=()):
    if not tree:
        yield cur
    else:
        for n, s in tree.items():
            for path in paths(s, cur+(n,)):
                yield path

结果:

>>> list(paths(tree))
[('0', 'A', 'B', 'C'), ('0', 'D', 'E'), ('0', 'D', 'F')]

请注意,我使用元组作为默认参数而不是列表,这是因为mutable default arguments can get you into trouble

【讨论】:

  • if not tree:... 我会将其更改为 if... else: 有两个原因:1) 更明确地说明这里发生的事情,以及 2) 这样None0、和 [] 也是有效的树结束状态。
  • @JoelCornett - 好主意,在我的回答中添加了else
  • 太棒了,我忘记了那个可变的默认参数。非常感谢。
【解决方案2】:

你可以使用类似这样的东西,类似于选择的答案。

 import collections

 def iter_paths(tree, parent_path=()):
     for path, node in tree.iteritems():
         current_path = parent_path + (path,)
         if isinstance(node, collections.Mapping):
             for inner_path in iter_paths(node, current_path):
                 yield inner_path
         else:
             yield current_path

对于以下字典:

tree = {'A':1, 'B':{'B1':1, 'B2':2}, 'C':{'C1':{'C11':1, 'C12':2},'C2':{'C21':1, 'C22':2}}}

输出应该是(yield order可能不同):

('A',)
('C', 'C2', 'C22')
('C', 'C2', 'C21')
('C', 'C1', 'C12')
('C', 'C1', 'C11')
('B', 'B1')
('B', 'B2')

【讨论】:

  • 自从我看到这个问题已经 5 年了,很高兴看到仍然有解决方案被发布;)作为旁注,我一直在阅读 Fluent Python,今天我做了 Goose Typing。很高兴看到您正在使用它。
【解决方案3】:

假设树结构是这种格式: {'0':{'A':{},'B':{}}} 那么这样的事情应该可以解决问题。

def paths(nodeId, children, ancestors, allPaths):
    ancestors.append(nodeId)
    if len(children) == 0:
        allPaths.append(ancestors)
    else:
        for childId in children:
            paths(childId, children[childId], ancestors[:], allPaths)

allPaths = []
paths('0', tree['0'], [], allPaths)

类似的东西应该可以。通常我会先试试这个,但我现在在我的 iPad 上。如果它不起作用,它应该会给你一些想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 2015-10-03
    相关资源
    最近更新 更多