Python list of lists 递归增加了额外的嵌套

Python list of lists recursion adds extra nesting

我正在尝试解决与此处列出的问题类似的问题:Python: Combinations of parent-child hierarchy

graph = {}

nodes = [
('top','1a'),
('top','1a1'),
('top','1b'),
('top','1c'),
('1a','2a'),
('1b','2b'),
('1c','2c'),
('2a','3a'),
('2c','3c'),
('3c','4c')
]

for parent,child in nodes:
    graph.setdefault(parent,[]).append(child)

def find_all_paths(graph, start, path=[]):
    path = path + [start]

    if not graph.has_key(start):
        return path

    paths = []

    for node in graph[start]:
        paths.append(find_all_paths(graph, node, path))

    return paths

test = find_all_paths(graph, 'top')

期望的输出:

[['top', '1a', '2a', '3a'],
 ['top', '1a1'],
 ['top', '1b', '2b'],
 ['top', '1c', '2c', '3c', '4c']]

实际输出:

[[[['top', '1a', '2a', '3a']]],
 ['top', '1a1'],
 [['top', '1b', '2b']],
 [[[['top', '1c', '2c', '3c', '4c']]]]]

关于如何删除额外嵌套的任何建议?谢谢!

以下应该可以解决您的问题:

 def find_all_paths(graph, start, path=None):
    if path is None: 
        # best practice, avoid using [] or {} as
        # default parameters as @TigerhawkT3 
        # pointed out.
        path = []
    path = path + [start]

    if not graph.has_key(start):
        return [path] # return the path as a list of lists!

    paths = []
    for node in graph[start]:
        # And now use `extend` to make sure your response
        # also ends up as a list of lists
        paths.extend(find_all_paths(graph, node, path))

    return paths

问题是 path(单个列表)和 paths(列表的列表)之间的混淆。您的函数可以 return 任意一个,具体取决于您在图表中的位置。

您可能想要 return 所有情况下的路径列表。因此,将基本案例中的 return path 更改为 return [path].

在递归情况下,您现在需要处理将每个 child 的路径合并在一起的问题。我建议使用 paths.extend(...) 而不是 paths.append(...).

将所有这些放在一起,您会得到:

def find_all_paths(graph, start, path=[]):
    path = path + [start]

    if not graph.has_key(start):
        return [path]

    paths = []

    for node in graph[start]:
        paths.extend(find_all_paths(graph, node, path))

    return paths

这是一个 non-recursive 解决方案。但是,它 "cheats" 通过对输出列表进行排序。

def find_all_paths(edges):
    graph = {}
    for u, v in edges:
        if u in graph:
            graph[v] = graph[u] + [v]
            del graph[u]
        else:
            graph[v] = [u, v]
    return sorted(graph.values())

data = (
    ('top','1a'),
    ('top','1a1'),
    ('top','1b'),
    ('top','1c'),
    ('1a','2a'),
    ('1b','2b'),
    ('1c','2c'),
    ('2a','3a'),
    ('2c','3c'),
    ('3c','4c'),
)

test = find_all_paths(data)
for row in test:
    print(row)

输出

['top', '1a', '2a', '3a']                                                                                                                      
['top', '1a1']                                                                                                                                 
['top', '1b', '2b']                                                                                                                            
['top', '1c', '2c', '3c', '4c']