如何从Adjacency列表递归生成父子字符串列表?

时间:2015-06-02 20:36:03

标签: python recursion adjacency-list

要点:

我正在尝试创建一个递归函数,从邻接列表中获取数据并将其转换为点表示法。

详细说明:

我将这些数据作为元组列表(Python)。数据按id排序,但这是唯一的限制。父母必须在孩子面前列出是没有限制的:例如,项目#3可以有父项,即项目#7。世代数也没有(计划)限制。

id     name     parent  |  data = [
1      A        0       |          (1, 'A', 0),
2      B        1       |          (2, 'B', 1),
3      C        1       |          ...
4      D        2       |
5      E        2       |
6      F        3       |
7      G        2       |
8      H        6       |          ...
9      I        4       |          (9, 'I', 4)]

我想以父子点符号返回字符串列表:

A
A.B
A.B.D
A.B.D.I
A.B.E
A.B.G
A.C
A.C.F
A.C.F.H

请注意,每个名称都会显示 - 我找到的其他算法只返回没有孩子的项目。

我尝试过的事情:

Python代码:

这是我迄今为止所获得的,基于USF的数据结构可视化here

if len(cat_list) == 0:
    return

for item in cat_list:
    parent_id = item[0]
    name = item[1]
    children = [_x for _x in cat_list if _x[2] == parent_id]

    if len(children) == 0:
        # then we're at the end
        return name
    else:
        sub_problem = cat_list[1:]
        sub_solution = create_categories(sub_problem)
        solution = "{}.{}".format(name, sub_solution)
        print(solution)
        return solution

但所有这一切都需要一个项目并一直建立它:

D.E
C.D.E
B.C.D.E
A.B.C.D.E

SQL:

如果数据存储在SQLite数据库中,并且可以使用以下SQL部分存储:

SELECT
    t1.name AS level1,
    t2.name as level2,
    t3.name as level3,
    t4.name as level4
FROM category AS t1
    LEFT JOIN category AS t2 ON t2.parent = t1.id
    LEFT JOIN category AS t3 ON t3.parent = t2.id
    LEFT JOIN category AS t4 ON t4.parent = t3.id
WHERE t1.name = 'A'

但这有多个问题:

  1. 无法扩展到任意深度
  2. 不返回中间深度
  3. 由于这些限制,我决定用Python实现代码。

    研究

    我看了很多不同的问题和网站,但没有一个给我“Eureka”时刻,因此我在这里问。

    This question非常相似,但在vb.net中,我一无所知。它也没有通知我如何执行连接。

    This question也很相似,但我又不知道这种语言。好像Lookup函数可能非常类似于python dict ...

2 个答案:

答案 0 :(得分:1)

数据准备步骤有点可怕,因为你的ID从我们需要阻塞元素的位置开始,位置0处的无:

original = [(1, 'A', 0),
            (2, 'B', 1),
            (3, 'C', 1),
            (4, 'D', 2),
            (5, 'E', 2),
            (6, 'F', 3),
            (7, 'G', 2),
            (8, 'H', 6),
            (9, 'I', 4)]
ids,data,parents = zip(*original)
data =[None]+list(data)
parents = [None]+list(parents)

一旦您以正确的格式获取输入数据,此代码将起作用:

ids = range(1,10)
parents = [None,0,1,1,2,2,3,2,6,4]
data =[None,"A","B","C","D","E","F","G","H","I"]

def get_parents(node):
    if not parents[node]:
        return data[node]
    return get_parents(parents[node])+data[node]
for id in ids:
    print ".".join(list(get_parents(id)))
>>> 
A
A.B
A.C
A.B.D
A.B.E
A.C.F
A.B.G
A.C.F.H
A.B.D.I

答案 1 :(得分:0)

在一张纸上写下每一步后,我能够提出以下内容:

def generate_category_strings(cat_list, parent_item, sent_str, retlist=[]):
    """
    Concatenates categories together and returns a list of them.
    """
    if parent_item is None:
        parent_item = cat_list[0]
        retlist.append(parent_item[1])

    parent_id = parent_item[0]
    parent_name = parent_item[1]

    if sent_str is None:
        sent_str = parent_name

    children = [_x for _x in cat_list if _x[2] == parent_id]

    if len(children) == 0:
        # base case, no children
        return ["{}.{}".format(sent_str, parent_name)]
    else:
        for child in children:
            str_to_send = "{}.{}".format(sent_str, child[1])
            retlist.append(str_to_send)
            generate_category_strings(cat_list, child, str_to_send, retlist)
        return retlist

在原始数据集上运行:

data = [(1, "A", 0), (2, "B", 1), (3, "C", 1), (4, "D", 2),
        (5, "E", 2), (6, "F", 3), (7, "G", 2), (8, "H", 6),
        (9, "I", 4),
       ]

a = generate_category_strings(data, None, None)
for item in a:
    print(item)

打印:

A
A.B
A.B.D
A.B.D.I
A.B.E
A.B.G
A.C
A.C.F
A.C.F.H