如何在 python 中从字典中打印树

How to print tree from dictionary in python

我正在尝试在 python 中实现 ldd 类应用程序。但是,我正在努力将数据表示为树状结构。 linux 库依赖于其他一些库,所以我的任务是跟踪依赖列表,直到找不到依赖为止。 我在下面显示的字典中有数据,

{lib_A: [lib_1, lib_2, lib_3, lib_4], lib_1: [lib_x, lib_y, lib_z], lib_x: [lib_i], lib_y: [lib_p], lib_2: [lib_a, lib_b], lib_a: [lib_11]......}

其中 lib_1, lib_2, lib_3,而 lib_4 取决于 lib_A。那么lib_xlib_y,还有lib_zlib_1 等等。该列表一直持续到找不到依赖项为止。如果我在 for 循环中打印数据,输出如下所示,

for lib, dep_lib in dependency_dict.items():
    print(lib, dep_lib)
lib_A [lib_1, lib_2, lib_3, lib_4]
lib_1 [lib_x, lib_y, lib_z]
lib_x [lib_i]
lib_y [lib_p]
lib_2 [lib_a, lib_b]
lib_a [lib_11]
...
..

我想将上述数据表示为树状结构,如下所示。

lib_A <= lib_1
         <= lib_x
            <= lib_i
         <= lib_y
            <= lib_p
         <= lib_z
      <= lib_2
         <= lib_a
            <= lib_11
         <= lib_b
      <= lib_3
      <= lib_4


在处理基于树的结构时,通常很自然地使用递归函数来处理它。为了产生你想要的输出,我会写这样的东西:

def process_lib(data, lib, padding=0):
    if padding == 0:
        print(lib)
    else:
        print(" "*padding, "<=", lib)

    for child in data.get(lib, []): # base case: lib is not in the dict
        process_lib(data, child, padding + 3)  # recursive case

这并没有完全复制您的示例的第一行,因为我们将 lib_A 放在单独的一行,而 lib_1 放在下一行。您可以为 padding == 0 案例添加更多特殊案例逻辑,并弄清楚如何让第一个 child 直接跟随它,但希望这个输出足够好:

lib_A
    <= lib_1
       <= lib_x
          <= lib_i
       <= lib_y
          <= lib_p
       <= lib_z
    <= lib_2
       <= lib_a
          <= lib_11
       <= lib_b
    <= lib_3
    <= lib_4

此代码可能只适用于简单的树。如果您的真实数据是一个更复杂的图形,在依赖层次结构中的多个点显示相同的库,那么您需要更复杂的东西。您需要跟踪已经看到哪些节点,或者根本不再打印它们,或者打印它们但不打印它们的依赖关系。这是执行后者的实现:

def process_lib(data, lib, padding=0, seen=None):
    if seen is None:
        seen = set()
    if padding == 0:
        print(lib)
    else:
        print(" "*padding, "<=", lib)

    if lib in seen:
        print(" "*(padding+3), "<= ...") # alternate base case
    else:
        seen.add(lib)
        for child in data.get(lib, []):
            process_lib(data, child, padding + 3, seen)

如果您根本不想重复,请使用:

def process_lib(data, lib, padding=0, seen=None):
    if seen is None:
        seen = set()
    if padding == 0:
        print(lib)
    else:
        print(" "*padding, "<=", lib)

    seen.add(lib)
    for child in data.get(lib, []):
        if child not in seen:
            process_lib(data, child, padding + 3, seen)