我在编写可读取员工/经理CSV的算法并输出包含员工/经理关系的有向图时遇到麻烦。
我的foobar示例:给出以下CSV文件
john,
jill, john
tom, john
tim, jill
felisa, tom
ray, tom
bob, tim
jim, tim
pam, felisa
ben, ray
james, ray
mike, pam
rashad, ben
henry, james
如何构建DiGraph以便可以显示以下组织结构:
john
/ \
jill tom
/ / \
tim felisa ray
/ \ / / \
bob jim pam ben james
/ / \
mike rashad henry
显然这是一个图形问题,但是我在决定使用哪种结构时遇到了麻烦(例如,最好使用dict
还是构建自定义OrganizationalGraph
对象等)。任何帮助表示赞赏。
选择的语言并不是很重要(尽管我们可以简单地说Python [相应地更新标签]),但我更想尝试理解此类问题的基础(例如,递归vs.迭代,使用set()
来存储经理的直接报告,而不是仅使用 抽象数据结构)。 最后,不,使用标准库之外的任何软件包都是初学者。
答案 0 :(得分:4)
要构建图,我们将获得以下信息:
请注意,在您的问题示例csv
中,您似乎将felisa
拼写为felia
。结果,这些输出不是您输入的实际数据,而是校正后的版本。
首先,我们解析csv
文件,提取根和边列表:
import csv
with open('data.csv') as f:
f = list(csv.reader(f, skipinitialspace=True))
root, *edges = f
root = root[0]
print(root)
print(edges)
输出:
john
[['jill', 'john'], ['tom', 'john'], ['tim', 'jill'], ['felisa', 'tom'], ['ray', 'tom'], ['bob', 'tim'], ['jim', 'tim'], ['pam', 'felisa'], ['ben', 'ray'], ['james', 'ray'], ['mike', 'pam'], ['rashad', 'ben'], ['henry', 'james']]
我们使用defaultdict
(标准库)中的collections
来表示图形。我们在字典中使用key
代表父母/管理者,并使用value
代表孩子/雇员的列表:
from collections import defaultdict
graph = defaultdict(list)
for child, parent in edges:
graph[parent].append(child)
print(graph)
输出:
defaultdict(<class 'list'>, {'john': ['jill', 'tom'], 'jill': ['tim'], 'tom': ['felisa', 'ray'], 'tim': ['bob', 'jim'], 'felisa': ['pam'], 'ray': ['ben', 'james'], 'pam': ['mike'], 'ben': ['rashad'], 'james': ['henry']})
此结构使我们可以获取带有graph[node]
的节点的子级列表。我们知道,树的根是任何列表中任何值中都不存在的节点。我们还保存了较早的根。
我完全按照字面意思理解了“如何构建DiGraph以便显示以下组织结构”。这是一个示例,说明如何遍历此图结构以构建字符串表示形式:
res = ''
stack = [(root, 0)]
needed_lines = defaultdict(int)
while stack:
node, level = stack.pop()
prev_level = level-4
res += '\n' + ''.join('|' if i in needed_lines else
' ' if i <= level-4 else
'-' for i in range(level)) + node
for child in graph[node]:
stack.append((child, level+4))
needed_lines[level] += len(graph[node])
needed_lines[prev_level] -=1
if needed_lines[prev_level] == 0: del needed_lines[prev_level]
print(res)
输出:
john
|---tom
| |---ray
| | |---james
| | | |---henry
| | |---ben
| | |---rashad
| |---felisa
| |---pam
| |---mike
|---jill
|---tim
|---jim
|---bob
答案 1 :(得分:1)
很显然,您正在尝试构建树图。如果您不知道一个节点可以有多少个直接子级,则树的最常见表示形式是 node 对象的集合。 (如果您知道每个节点的子节点数上限,并且大多数节点具有那么多子节点,则可以在一个简单数组中高效表示树。)
每个节点有1个父级和一组子级,这由某种数据容器(通常是面向对象语言的Node类的Object)表示,该数据容器包含对父级和子级的引用或指针。通常,这是父引用的单个变量,子引用的数组。没有父节点的一个节点称为 root ,并存储在一个特殊变量中,该变量用于引用整个树。
您想对树进行排列,以便轻松找到具有名称的节点。遍历各种选项可能是一门完整的计算机科学课程,因此我在这里不做介绍。实际上,您可能最终会在第二种经过排序的数据结构中存储指向节点的指针,以便于快速找到它们。
然后为每个输入找到引用的父节点,并将指定的子节点添加到该父节点。例如,在处理jill, john
您
jill
的新节点john
的节点jill
添加到john
的子列表中jill
的父级设置为john
这能回答您的问题吗?