简体   繁体   中英

How can I convert a given list of lists to a tree structure in Python?

So I'm basically stuck at this problem. The problem gives us a parts inventory list where each component is made up of other components (in a tree relational manner). For example the input list can be given as

[["A",[2,"B"],[1,"C"]],
["B",[1,"D"],[1,"E"]],
["D",20.],
["E",10.]
["C",40.]]

, where A is made up of 2 Bs and 1 C, similarly B is made up of 1 D and 1 E. The lists with a float as the last index simply indicate the unit price of the given basic part.

The problem is, I need to convert this structure to a tree representation which can be written as;

[1,"A",[2,"B",[1,"D",20.],[1,"E",10.]], [1,"C",40.]]

where we simply bury the children of each node as a list in a nested list structure. In order to achieve this, I tried a recursive-iterative algorithm but as we don't know how many children a node has or what the depth of the tree is, I wasn't able to do so.

Can you recommend me a solution for this problem, thanks in advance.

PS: There is not a predefined order for the input list, its elements can be placed from bottom to top of the tree or shuffled.

If your input structure remains same then you can try something like

e = [["A",[2,"B"],[1,"C"]],
["B",[1,"D"],[1,"E"]],
["D",20.],
["E",10.],
["C",40.]]

record = {}

for i in reversed(e):
    if(len(i) == 2):
        record[i[0]] = i[1]
    else:
        # there is children
        temp = []
        for j in i[1:]:
            if(isinstance(record[j[1]], list)):
                temp.append([*j, *record[j[1]]])
            else:
                temp.append([*j, record[j[1]]])
        record[i[0]] = temp

root = e[0][0]
print([1, root, *record[root]])  

output

[1, 'A', [2, 'B', [1, 'D', 20.0], [1, 'E', 10.0]], [1, 'C', 40.0]]

Otherwise, you can create a Tree structure and get the output.

You can leverage the fact that lists are pointers to perform the linking in one pass by copying the children list references within the parent lists:

def buildTree(data):
    index = { c[0]:c for c in data }  # used to access components by their id
    root  = index.copy()              # used to retain top level component(s)

    for component in data:
        if isinstance(component[1],float): continue   # no linking on leaf items
        for i,(_,prod) in enumerate(component[1:],1): # expand children
            component[i][1:] = index[prod]            # embed child in parent
            root.pop(prod)                            # remove child from root

    return [[1,*rv] for rv in root.values()] # output root item(s)

output:

data = [["A",[2,"B"],[1,"C"]],
        ["B",[1,"D"],[1,"E"]],
        ["D",20.0],
        ["E",10.0],
        ["C",40.0]]

print(*buildTree(data))
# [1, 'A', [2, 'B', [1, 'D', 20.0], [1, 'E', 10.0]], [1, 'C', 40.0]]

Changing the order of the data does not change the result

data = [["D",20.0],
        ["E",10.0],
        ["B",[1,"D"],[1,"E"]],
        ["C",40.0],
        ["A",[2,"B"],[1,"C"]]]

print(*buildTree(data))
# [1, 'A', [2, 'B', [1, 'D', 20.0], [1, 'E', 10.0]], [1, 'C', 40.0]]

Note that, if your data has multiple root items, the function will output them all. In this instance there is only one so it printed only one root

without dictionaries

If you are not allowed to use dictionaries, you can still use this approach but you'll have to do a sequential search through the data to find products by their id:

def buildTree(data):
    roots  = data.copy() # used to retain top level component(s)
    for component in data:
        if isinstance(component[1],float): continue   # no linking on leaf items
        for i,(_,prod) in enumerate(component[1:],1): # expand children
            child = next(c for c in data if c[0]==prod) # find child with id
            component[i][1:] = child                  # embed child in parent
            roots.remove(child)                       # remove child from root
    return [[1,*rv] for rv in roots] # output root items

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM