简体   繁体   English

递归打印带有对象的家谱

[英]Recursively printing a family tree with objects

I need help with recursive representation of a family tree.我需要有关家谱的递归表示的帮助。 Here is the data:这是数据:

children_and_parents = {
    "Mary": ["Patricia", "Lisa"], 
    "Patricia": ["Barbara", "Helen", "Maria"], 
    "Maria": ["Keren", "Carol"], 
    "Barbara": ["Betty"]
}

I need to mention that the values are objects, so I need to call them children_and_parents["Maria"].child to get ['Patricia', 'Lisa'] .我需要提到这些值是对象,所以我需要将它们称为children_and_parents["Maria"].child来获取['Patricia', 'Lisa']

The recursive program I currently have:我目前拥有的递归程序:

def draw_family_tree(person, level=0):
    if person in children_and_parents:
        for i in range (len(children_and_parents[person].child)):
            print (" "*level, person)
            return draw_family_tree(children_and_parents[person].child[i], level+3) 

What it's currently doing is:它目前正在做的是:

Mary
   Patricia
      Barbara

but the result should be something like:但结果应该是这样的:

Mary
   Patricia
       Barbara
           Betty
       Helen
       Maria
           Keren
           Carol
   Lisa

I'm stuck at the beginning of the program.我被困在程序的开头。 If someone would be willing to help I would really appreciate it.如果有人愿意提供帮助,我将不胜感激。

Rough code: https://repl.it/repls/BlondCavernousExponents粗略代码: https : //repl.it/repls/BlondCavernousExponents

Finding the root of the tree is a good candidate for a separate operation.找到树的根是单独操作的一个很好的候选者。 In your example, we know it's "Mary" , so we can iterate accordingly.在您的示例中,我们知道它是"Mary" ,因此我们可以相应地进行迭代。 If it's not known, you can write a function to return the first parent node that isn't a child of any other node:如果不知道,您可以编写一个函数来返回第一个不是任何其他节点的子节点的父节点:

def find_root(tree):
    all_children = {x for y in tree.values() for x in y}
    
    for node in tree:
        if node not in all_children:
            return node

As for the actual printing procedure, try printing the parent node before iterating over children.至于实际的打印过程,在迭代子节点之前尝试打印父节点。 I also recommend passing the tree as a parameter to the function to maintain encapsulation and keep it reusable (ie not dependent on some variable called children_and_parents existing in the calling scope).我还建议将树作为参数传递给函数以维护封装并使其可重用(即不依赖于调用范围中存在的一些名为children_and_parents变量)。

def draw_family_tree(tree, root, gap=3, level=0):
    if root:
        print(" " * level + root)

        if root in tree:
            for child in tree[root]:
                draw_family_tree(tree, child, gap, level + gap)

We can also avoid the side effect in draw_family_tree and have it return a generator, letting the caller decide what to do with the result:我们还可以避免draw_family_tree中的draw_family_tree并让它返回一个生成器,让调用者决定如何处理结果:

def find_root(tree):
    all_children = {x for y in tree.values() for x in y}
    
    for node in tree:
        if node not in all_children:
            return node

def draw_family_tree(tree, root, gap=3, level=0):
    if root:
        yield " " * level + root

        if root in tree:
            for child in tree[root]:
                yield from draw_family_tree(tree, child, gap, level + gap)

if __name__ == "__main__":
    children_and_parents = {
        "Mary": ["Patricia", "Lisa"], 
        "Patricia": ["Barbara", "Helen", "Maria"], 
        "Maria": ["Keren", "Carol"], 
        "Barbara": ["Betty"]
    }
    root = find_root(children_and_parents)

    for node in draw_family_tree(children_and_parents, root):
        print(node)

Output:输出:

Mary
   Patricia
      Barbara
         Betty
      Helen
      Maria
         Keren
         Carol
   Lisa

As mentioned in an earlier discussion, I don't recommend using a class for a simple <string, list> pair;正如前面的讨论中提到的,我不建议将一个类用于简单的<string, list>对; it adds a lot of verbosity without functionality and is actually a bit misleading, because parent suggests the person has a parent (it's actually referring to the name of the person represented by the object).它增加了很多没有功能的冗长,实际上有点误导,因为parent暗示这个人有一个父母(它实际上是指对象所代表的人的名字)。 If you do choose to go this route, you'll need to append .child to all of the bracket accesses and write a __repr__(self) function for your class (or print(root.parent) .如果您确实选择走这条路线,则需要将.child附加到所有括号访问并为您的类(或print(root.parent)编写一个__repr__(self)函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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