我正在做一些关于节点树的工作,我被这个问题困住了。这个列表包含了树的所有信息:
connections = ['Module/Expr/ListComp/BinOp/Name/id/i/',
'Module/Expr/ListComp/BinOp/Sub/',
'Module/Expr/ListComp/BinOp/Num/0.5/',
'Module/Expr/ListComp/comprehension/Name/id/i/',
'Module/Expr/ListComp/comprehension/Name/id/inp/']
我需要把它转换成:
{'Module':'Expr', 'Expr':'ListComp', 'ListComp':'BinOp comprehension',
'BinOp':'Name Sub Num', 'Name':'id', 'id':'i', 'Num':'0.5',
'comprehension':'Name', 'Name':'id', 'id':'i inp'}
目标是将连接解析成结构{'parent':'child(s)'}
的字典。为了做到这一点,我已经试过了:
rules = {}
connections_list = [[word for word in path.split("/") if word] for path in connections]
for path in connections_list:
for i, word in enumerate(path):
same_level = [y[i+1] for y in connections_list if len(connections_list) > i+1]
if same_level:
unique_on_level = list(set(same_level))
rules.update({word:" ".join(unique_on_level)})
else:
pass
break
print(rules)
输出:
{'Module': 'Expr',
'Expr': 'ListComp',
'ListComp': 'BinOp comprehension',
'BinOp': 'Num Sub Name'}
我无法想出这样做的方法,这里的问题发生在最后一个节点周围,但我不知道如何解决它,任何关于如何解决这个问题的想法?
首先创建父节点到子节点的映射,然后删除副本。
rules = {}
for connection in connections:
parts = connection.rstrip("/").split("/")
for parent, child in zip(parts, parts[1:]):
if parent not in rules:
rules[parent] = []
rules[parent].append(child)
rules = {k: " ".join({}.fromkeys(v)) for k, v in rules.items()}
根据@wim的回答和评论,我认为这应该可行:
from collections import defaultdict
rule_data = defaultdict(set)
for connection in connections:
parts = connection.rstrip("/").split("/")
for level, (parent, child) in enumerate(zip(parts, parts[1:])):
rule_data[level, parent].add(child)
rules = [
(parent, " ".join(sorted(children)))
for (_level, parent), children in rule_data.items()
]
指出:
使用
set
会丢弃子进程的顺序;如果它很重要,我们可以使用dict
(或者,为了与旧版本的Python兼容,使用OrderedDict
):rule_data = defaultdict(dict)
rule_data[level, parent][child] = None
(parent, " ".join(children))
为了输出的稳定性,我对子进程进行排序,这样单元测试就可以很容易地工作,因此任何下游处理都不会看到虚假的变化。
正如@Prune所指出的,这似乎不是数据的自然表示:
- 你最终想要实现什么?
- 这里的
rule_data
中间变量在进一步处理中可能比最终形式更有用… - 如果任何连接包含空格,输出将是不明确的。
connections = ['Module/Expr/ListComp/BinOp/Name/id/i/',
'Module/Expr/ListComp/BinOp/Sub/',
'Module/Expr/ListComp/BinOp/Num/0.5/',
'Module/Expr/ListComp/comprehension/Name/id/i/',
'Module/Expr/ListComp/comprehension/Name/id/inp/']
splitted_conns = [conn.strip('/').split('/') for conn in connections]
res = {}
for conn in splitted_conns:
for root, child in zip(conn[:-1], conn[1:]):
res[root] = res.get(root, set()) | {child}
print(res)
输出:
{"模块":{"Expr"},"Expr":{"ListComp"},"ListComp":{"BinOp","理解"},"BinOp":{"子"、"Num","名字"},"名字":{"id"},"id":{"输入","我"},"Num":{"0.5"},"理解":{'名字'}}
像这样?您期望的输出包含重复的节点"id",我想这是一个错误,它不是吗?
关于解决方案,我决定为每个组un子使用一个集合,因此我们可以避免在其名称中包含空格的节点失败。此外,使用集合很容易避免重复。如果要将每个集合转换为空格分隔的字符串,可以尝试这样做:
{k: ' '.join(v) for k, v in res.items()}