简体   繁体   中英

Construct a genera- tree structure recursively in python?

I built this Node class:

 
class Node:
    """
    Node of Tree object:
    """

    def __init__(self, data):
        self.data = data
        self.parent = None
        self.children = list()

    def __repr__(self) -> str:
        return f"Node: {self.data}"

    def set_data(self, data):
        self.data = data

    def get_data(self):
        return self.data

    def set_children(self, *children):
        for child in children:
            child.parent = self
            assert isinstance(child, Node)
            self.children.append(child)

    def get_children(self):
        return self.children

    def set_parent(self, parent):
        assert isinstance(parent, Node)
        parent.set_children(self)

    def get_parent(self):
        return self.parent

    def get_root(self):
        if self.parent == None:
            return self
        p = self.get_parent()
        while bool(p.get_parent()):
            print(bool(p.get_parent()))
            p = p.get_parent()
        return p

    def is_root(self):
        if self.parent is None:
            return True
        return False

    def is_leaf(self):
        if self.children:
            return False
        return True

    def get_level(self):
        if self.is_root():
            return 0
        return 1 + self.parent.get_level()

    def print_tree(self) -> None:
        if self.parent:
            spaces = "|   " * self.get_level()
        prefix = spaces + "|-- " if self.parent else ""
        print(prefix + str(self.data))
        if self.children:
            for child in self.children:
                child.print_tree()

The problem I am facing is, how can I create nodes and assign parents or child to them using loops? I've tryed this:

root = a = Node(0)
for i in range(1, 10):
    new_node = Node(i)
    a.set_children(new_node)
    a = new_node

root.print_tree()

which works, printing:

0
|   |-- 1
|   |   |-- 2
|   |   |   |-- 3
|   |   |   |   |-- 4
|   |   |   |   |   |-- 5
|   |   |   |   |   |   |-- 6
|   |   |   |   |   |   |   |-- 7
|   |   |   |   |   |   |   |   |-- 8
|   |   |   |   |   |   |   |   |   |-- 9

BUT, I need a way to make nodes subscriptable in such a way that if I need to assign more children to a previous node, like the node 4. I could go back to it and assign them.

Maybe building a separete class that would assign indexes to the nodes or something like it idk.

The data that I want to transform into a tree comes in a csv file and is like this:

AUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AUG02;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;FNS_1700 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_1701 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_3352 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_89069 (TS);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_80304 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_660 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80079 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80412 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_14118 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_3008 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_3007 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_81391 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_17629 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_659 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_665 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_81106 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;FNS_80996 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80080 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_4139 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_17634 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_80081 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_2738 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_86546 (RA);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_4704 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_663 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_656 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_17637 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_3133 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_3000 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_80082 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AUG01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

You can use the following function:

def from_csv(csv):
    parent = root = Node(None) # dummy node
    curdepth = 0
    for line in csv.splitlines():
        depth = len(line) - len(line.lstrip(";"))
        while curdepth > depth:
            parent = parent.parent
            curdepth -= 1
        node = Node(line.strip(";"))
        node.set_parent(parent)
        parent = node
        curdepth += 1
    return root

Here is a demo run:

csv = """AUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AUG02;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;FNS_1700 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_1701 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_3352 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_89069 (TS);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_80304 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_660 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80079 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80412 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_14118 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_3008 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_3007 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_81391 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_17629 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_659 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_665 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_81106 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;FNS_80996 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_80080 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;FNS_4139 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_17634 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_80081 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_2738 (CD);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_86546 (RA);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_4704 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;FNS_663 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;FNS_656 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_17637 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_3133 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_3000 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;FNS_80082 (FU);;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AUG01;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
"""

root = from_csv(csv)
root.print_tree()

This outputs:

None
|   |-- AUG
|   |   |-- AUG02
|   |   |   |-- FNS_1700 (CD)
|   |   |   |   |-- FNS_1701 (CD)
|   |   |   |   |   |-- FNS_3352 (FU)
|   |   |   |   |   |-- FNS_89069 (TS)
|   |   |   |   |   |   |-- FNS_80304 (FU)
|   |   |   |   |   |   |-- FNS_660 (FU)
|   |   |   |   |   |   |   |-- FNS_80079 (FU)
|   |   |   |   |   |   |   |-- FNS_80412 (FU)
|   |   |   |   |   |   |-- FNS_14118 (FU)
|   |   |   |   |   |   |-- FNS_3008 (FU)
|   |   |   |   |   |   |-- FNS_3007 (FU)
|   |   |   |   |   |   |   |-- FNS_81391 (FU)
|   |   |   |   |   |   |-- FNS_17629 (FU)
|   |   |   |   |   |-- FNS_659 (FU)
|   |   |   |   |   |   |-- FNS_665 (FU)
|   |   |   |   |   |   |   |-- FNS_81106 (FU)
|   |   |   |   |   |   |   |   |-- FNS_80996 (FU)
|   |   |   |   |   |   |   |-- FNS_80080 (FU)
|   |   |   |   |   |   |   |-- FNS_4139 (FU)
|   |   |   |   |   |-- FNS_17634 (FU)
|   |   |   |   |   |-- FNS_80081 (FU)
|   |   |   |   |-- FNS_2738 (CD)
|   |   |   |   |-- FNS_86546 (RA)
|   |   |   |   |   |-- FNS_4704 (FU)
|   |   |   |   |   |-- FNS_663 (FU)
|   |   |   |   |   |   |-- FNS_656 (FU)
|   |   |   |   |-- FNS_17637 (FU)
|   |   |   |   |-- FNS_3133 (FU)
|   |   |   |   |-- FNS_3000 (FU)
|   |   |   |   |-- FNS_80082 (FU)
|   |   |-- AUG01

This includes a root with value None , because in theory it is possible that the CSV format defines multiple nodes at the top level, so it would represent a forest . The dummy root will then take those top level nodes as its children. If you expect only one top level node in the CSV input, then do:

root = from_csv(csv).get_children()[0]
root.parent = None
root.print_tree()

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-2025 STACKOOM.COM