Python 在列表树的通用(非二进制)列表中列出叶子的所有路径

Python 在列表树的通用(非二进制)列表中列出叶子的所有路径,python,tree,Python,Tree,我有一棵这样编码的树: [A, [B, [G, [H], [I]]], [D, [C], [E], [F]]] 这代表了以下结构: A / \ B D / /|\ G C E F / \ H I 此外,叶子都包含“end”,而不是实际的字母,因此H、I、C、E、F实际上都是“end” 查看列表的另一种方式可能更直观。在这种情况下,缩进表示树级别 [A, [B, [G,

我有一棵这样编码的树:

[A, [B, [G, [H], [I]]], 
    [D, [C], [E], [F]]]
这代表了以下结构:

        A
       / \
      B   D
     /   /|\
    G   C E F
   / \
  H   I
此外,叶子都包含“end”,而不是实际的字母,因此H、I、C、E、F实际上都是“end”

查看列表的另一种方式可能更直观。在这种情况下,缩进表示树级别

[A, 
    [B, 
        [G, 
            [H], 
            [I]
        ]
    ], 
    [D, 
        [C], 
        [E], 
        [F]
    ]
]
我要遍历树并列出所有到叶子的路径

[A, B, G, H]
[A, B, G, I]
[A, D, C]
[A, D, E]
[A, D, F]
我编写了这个函数,它可以遍历树并正确识别树叶,但我不确定如何按照上面的列表构建路径:

def leave_paths(lst, level=0):
    #level is used to keep track how far in the tree we are to
    #perform various functions - removed here for simplicity
    if lst[0] == 'end':
        #This is a leaf!
    for i, l in enumerate(lst[1:]): 
        if type(l) is list:
            leave_paths(l, level + 1)

据我所知,这是正确的,但我不确定如何跟踪路径,以便按照我描述的方式对其进行格式化。

使用递归,您应该确定基本情况,然后如何使用简单的单个步骤来构建基本情况,以便生成更复杂的情况

基本情况: 叶子是每个路径的唯一部分,这似乎是一条线索,可以在构建路径时从叶子开始。将包含叶的列表作为返回值传递回,这是基本情况。在只有一个节点的情况下,在单个列表(只有一条路径)中只有一个值

递归案例:您需要获得递归的结果(根据您的示例,最多2个分支),然后将当前节点前置到每个子节点的结果列表中(可能超过2个,除非当前节点下没有分支)。在预结束后返回结果

编辑:既然您很好地要求获得一些代码,下面是您可以做的:

def leave_paths(current):
    # Identify leaves by their length
    if len(current) == 1:
        return current
    # Take all branches, get the paths for the branch, and prepend current
    return [[current[0]] + path for branch in current[1:] for path in leave_paths(branch)]

这将为您提供一个“路径”列表列表。请注意,我们是如何在每个递归步骤中通过迭代
分支
es,然后也迭代每个
分支
的结果
路径
s来实现平坦化的,并将预先添加的结果作为返回值放入单个结果
列表中。

以下是两个用例的更适用的复制粘贴答案,基于机器渴望的答案(主要是答案的副本):

创建一个长字符串的路径,例如。['ABCDE']

def leave_paths(current):
    # Identify leaves by their length
    if len(current) == 1:
        return current

    # Take all branches, get the paths for the branch, and prepend 
    return [current[0] + path for branch in current[1:] for path in leave_paths(branch)]
如果您希望路径作为列表,例如[a'、'B'、'C'、'D'、'e']

def leave_paths(current):
    # Identify leaves by their length
    if len(current) == 1:
        return [current]

    # Take all branches, get the paths for the branch, and prepend 
    return [[current[0]] + path for branch in current[1:] for path in leave_paths(branch)]

输入中的
H
I
在哪里?我不明白列表是如何编码树的。很抱歉,修复了。基本上,每次列表开始时,它都是树中的一个新级别。每个列表都由父节点(不是列表)和它的所有子节点组成。每个子级都是一个列表,因为它是不同级别的树。请在代码上添加一些注释:在Python中,显式类型检查通常是一种代码味道。另外,不要使用小写L作为标识符,它看起来太像其他字符,使代码难以阅读/导致歧义。最后,不要使用类似于内置函数的标识符,例如
列表
构造函数:您可能会意外地键入错误
lst
,并最终导致难以追踪的错误。该函数用于解决“您尝试了什么”类型的问题,我没有与之结合:)例如,这是我尝试的逻辑,我可以简单地将类型检查更改为其他等效项。那么,仅仅将路径作为返回值传递回去有什么问题呢?尽管我非常感激这个答案,并且我希望它对我有用,但事实并非如此。我从理论上理解我必须做什么。对于我来说,弄清楚如何以适当的方式通过递归传递路径部分是不直观的。在发布之前,我已经试着弄清楚这一点。此外,树可以具有任意深度。我想你的回答表明实现是微不足道的,在这种情况下,为什么不发布它呢?如果实现不是微不足道的,那么显然这种类型的答案是没有帮助的,因为困难的部分是实现:)我将添加一些可以在程序中使用的示例代码。我想避免给你一个完整的实现,因为,尽管这是一个麻烦,但将非正式规范翻译成代码是开发过程中非常重要的一部分。我不认为我最初的答案是无用的,因为将任务作为非正式的规范用文字表达是更重要的一部分。如果你已经这样做了,你应该把它贴在你的问题上。当然,这取决于我的目标。当我在stackoverflow上发帖的时候,我已经在合理的时间范围内用尽了我所能完成的一切。我理解这个目标,并且最终可能自己解决它,但可能比我不经常处理的更习惯递归逻辑的人慢得多。但我编写了生成原始列表的函数,因此我当然可以沿着所有路径遍历此树并跟踪它们-但只能以基本上复制现有结构的方式进行。我理解,当然,您可能在实现步骤中遇到问题,我只是不想仓促行事,以防你觉得自己有能力去做。请参阅对文章的编辑以了解可能的实现。我还没有测试过它,但也许你已经有了足够的想法,可以用你的代码来尝试一下。你熟悉列表理解是如何工作的吗?是的,我对python并不陌生,我只是不经常处理递归逻辑——可能在一段时间内不会想到这个解决方案,但现在我永远都知道了:)。实际上,您的答案没有立即起作用
只能将list(而不是“str”)连接到list
,因为理解返回的“A”、“B”、“C”等都是字符串,但是将
[current[0]]
更改为
current[0]
可以修复它。谢谢