例如,有以下依赖: A< -B,C< -H,B< -F,B< -G,A< -C&C,A< -D,A< -E 我想将这些依赖转换为这样的多路树:
A
/ / \ \
B C D E
/\ /
F G H
有人会有一个好的方法吗?
答案 0 :(得分:0)
python中的解决方案。
每个依赖都是从孩子到他父母的边缘,例如A <- B
表示节点B
是节点A
的子节点,并且您有B
到A
的边缘。
话虽这么说,您需要一个数据结构来存储这些节点和边。
第一个解决方案是一个简单的词典。我们走吧。
首先,您必须以可用的格式解析依赖项。我提出了一种格式(父,子)和一个列表解析来解析字符串(这很容易翻译成任何高级语言):
def get_deps(dep_strings):
"""Return list of tuples (parent, child). Very rudimentary."""
return [tuple(dep_list) for dep_string in dep_strings.split(",") for dep_list in [dep_string.strip().split("<--")]]
其次,你必须遍历依赖项来构建树(这是算法的核心,并且很容易在任何高级语言中翻译):
def parse_to_dict(dep_strings):
deps = get_deps(dep_strings)
# the dict will take associate to every parent its "children dictionaries"
d = {}
for (p, c) in deps:
if p not in d: # parent has not yet been seen
d[p] = {}
if c not in d: # child has not yet been seen
d[c] = {} # child is a leaf, until it becomes possibly a parent
d[p][c] = d[c] # hang the child to its parent.
# the dict has a key for every node, and the value is its "children dictonaries".
# usually, we don't need this direct access, thus we remove all non root elements
for _, c in deps:
del d[c]
return d
由于为每个未知节点创建一个空的dict很麻烦,您可以使用defaultdict
或dict.setdefault
使其更具可读性。
...
d = defaultdict(dict) # will create an empty dict for every missing key
for (p, c) in deps:
d[p][c] = d[c] # hang the child to its parent, create dicts on demand.
或者
...
d = {}
for (p, c) in deps:
d.setdefault(p, {}) # will create an empty dict if this key is missiing
d.setdefault(c, {})
d[p][c] = d[c] # hang the child to its parent, create dicts on demand.
请注意dict.setdefault
更灵活,因为它可以接受参数,稍后您将看到。
如果要构建自定义树,则必须创建Node
类,例如:
class Node():
"""A very simple node class"""
def __init__(self, id):
self.__id = id
self.__children = []
def add(self, n):
self.__children.append(n)
def __str__(self):
if self.__children:
return "Node {} [{}]".format(self.__id, ", ".join(str(c) for c in self.__children))
else:
return "Leaf {}".format(self.__id)
创建树将与字典一样简单:
...
# we still need a dict
d = {}
for (p, c) in deps:
d.setdefault(p, Node(p)) # we need to build a node with an id,
d.setdefault(c, Node(c)) # hence defaultdict is not the right tool
d[p].add(d[c])
# dict
{'A': {'B': {'F': {}, 'G': {}}, 'C': {'H': {}}, 'D': {}, 'E': {}}}
# defaultdict
defaultdict(<class 'dict'>,
{'A': {'B': {'F': {}, 'G': {}}, 'C': {'H': {}}, 'D': {}, 'E': {}}})
# dict.setdefault
{'A': {'B': {'F': {}, 'G': {}}, 'C': {'H': {}}, 'D': {}, 'E': {}}}
# Node
Node A [Node B [Leaf F, Leaf G], Node C [Leaf H], Leaf D, Leaf E]