gpt4 book ai didi

python - 将嵌套 python 列表简化为结构化树的最佳方法(同时保留顺序)

转载 作者:太空宇宙 更新时间:2023-11-04 04:02:11 25 4
gpt4 key购买 nike

假设我有一个 Python 3.6 列表,如下所示:

l1 = [
[a,b,c],
[b,c],
[c],
[d, e],
[e]
...
]

我需要使用 anytree 将其转换为树状结构,所以它看起来像这样:

>>> print(RenderTree(l1))

l1
|__ a
| |__b
| |__c
|___d
|__e

考虑对象 abcde成为一个字符串,如果有任何帮助的话。我目前已经阅读了很多关于 anytree 的文档,并在 StackOverflow 上搜索了一段时间,但找不到任何可以帮助我解决该问题的内容。解决此问题的最 pythonic 方法是什么?

编辑:为了补充说明,原始列表 l1 应该表示一棵树,其中 l1 中的第一个元素是父节点,其中的每个节点是子节点。每个子节点都可以是它之前节点的子节点,以此类推

编辑编辑:所以,这是原始列​​表(假设)的样子:

l1 = [
['a', 'b', 'c'],
['b', 'c'],
['c'],
['d', 'e'],
['e']
]

在这里,每个子列表的第一个元素总是最终成为该分支的父元素。将这些分支中的每一个连接在一起将使我获得所需的格式,但我一直在努力将其表达出来(现在是凌晨 2 点)。以下是我的一些尝试:

将列表转换为节点:

from anytree import Node

l = []

for x in l1:
a = Node(x[0])
for i in x[1:]:
Node(i, parent = a)
l.append(a)

然而,这会返回一个树/列表:


>>> l
[Node('/a'), Node('/b'), Node('/c'), Node('/d'), Node('/e')]
>>> print(RenderTree(l[0]))
Node('/a')
├── Node('/a/b')
└── Node('/a/c')
>>> print(RenderTree(l[1]))
Node('/b')
└── Node('/b/c')
>>> print(RenderTree(l[2]))
Node('/c')
>>> print(RenderTree(l[3]))
Node('/d')
└── Node('/d/e')
>>> print(RenderTree(l[4]))
Node('/e')

为了过滤掉它,我尝试执行以下操作:

def tuple_replace(tup, pos, val):
return tup[:pos] + (val,) + tup[pos+1:]

>>> l2=[]
>>> for pos, x in enumerate(l):
for pos_2, i in enumerate(x.children):
for j in l[pos+1:]:
if j.name == i.name:
x.children = tuple_replace(x.children, pos_2, i)
break
l2.append(x)

>>> for x in l2:
print(RenderTree(x))


Node('/a')
├── Node('/a/b')
└── Node('/a/c')
Node('/a')
├── Node('/a/b')
└── Node('/a/c')
Node('/b')
└── Node('/b/c')
Node('/d')
└── Node('/d/e')

这是我目前所处的步骤

编辑编辑编辑:

所以,树的表示方式是我有一个函数返回一个像 l1 这样的列表,它背后有以下逻辑:

列表中的每个元素都有两部分。 parent ,和 child 。父元素是列表中的第一个元素,其他所有元素都是它的子元素,或者它是子元素的子元素等等。所以像这样的元素:[a, b, c][d, e, f, g] 代表分支中的所有元素,而不仅仅是直接父元素继续往下走。这就是其余元素发挥作用的地方。下一个元素通常包含父元素的第一个子元素:[b, c][e, f][g]。但是现在,元素 [d, e, f, g] 不同于 [a, b, c] 因为它里面有 2 个不同的子分支而不是一。所以,像这样的树:

l1
|
|_a
| |__b
| |__c
|
|_d
|__e
| |__f
|__g

将被描述为:

编辑:修复了输入树,因为 f 没有独立的分支

l1=[
[a,b,c],
[b, c],
[c],
[d,e,f,g],
[e,f]
[f]
[g]
]

最佳答案

您可以使用递归构建一个嵌套字典来表示您的树,然后遍历结果以打印所需的图表:

from functools import reduce
data = [['a', 'b', 'c'], ['b', 'c'], ['c'], ['d', 'e'], ['e']]
new_data = [a for i, a in enumerate(data) if all(a[0] not in c for c in data[:i])]
def to_tree(d):
return d[0] if len(d) == 1 else {d[0]:to_tree(d[1:])}

tree = reduce(lambda x, y:{**x, **y}, [to_tree(i) for i in new_data])

现在,打印结构:

import re
def print_tree(d, c = 0):
for a, b in d.items():
yield f'{"|" if c else ""}{" "*c}|__{a}'
if not isinstance(b, dict):
yield f'{"|" if (c+1) else ""}{" "*(c+1)}|__{b}'
else:
yield from print_tree(b, c+1)

*r, _r = print_tree(tree)
print('l1\n{}\n{}'.format('\n'.join(r), re.sub("^\|", "", _r)))

输出:

l1
|__a
| |__b
| |__c
|__d
|__e

编辑:可选的树形成方法:

当前的 to_tree 方法假定父子节点结构将全部包含为每个父节点的单个列表,即 ['a', 'b', 'c' ] 是树的完整路径,['d', 'e'] 也是完整路径。如果 future 的输入可能不是这种情况,您可以使用下面的代码来构建字典:

def to_tree(d, s, seen = []):
_l = [b for a, b, *_ in d if a == s and b not in seen]
return s if not _l else {s:to_tree(d, _l[0], seen+[s, _l[0]])}

data = [['a', 'b', 'c'], ['b', 'c'], ['c'], ['d', 'e'], ['e']]
p = [a[0] for i, a in enumerate(data) if all(a[0] not in c for c in data[:i])]
c = [i for i in data if len(i) > 1]
tree = reduce(lambda x, y:{**x, **y}, [to_tree(c, i) for i in p])

关于python - 将嵌套 python 列表简化为结构化树的最佳方法(同时保留顺序),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58046244/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com