[英]python - Convert list of dicts to hierarchy/multiple nested dicts - issue with orders
[英]Python Convert flat list of dicts to hierarchy tree
我在嘗試轉換以下列表時遇到了麻煩:
lst = [
{"id": 0, "job": "CEO", "ManagerID": 0, "name": "John Smith"},
{"id": 1, "job": "Medical Manager", "ManagerID": 0, "name": "Medic 1"},
{"id": 2, "job": "Medical Assist", "ManagerID": 1, "name": "Medic 2"},
{"id": 3, "job": "ICT Manager", "ManagerID": 0, "name": "ICT 1"},
{"id": 4, "job": "ICT Assist", "ManagerID": 3, "name": "ICT 2"},
{"id": 5, "job": "ICT Junior", "ManagerID": 4, "name": "ICT 3"}
]
變成喜歡的格式
output = [
{"id": 0, "job": "CEO", "ManagerID": 0, "name": "John Smith", "children" : [
{ "id":1, "job": "Medical Manager", "name": "Medic 1", "children" : [
{"id": 2, "job": "Medical Assist", "name": "Medic 2"}
]
},
{"id": 3, "job": "ICT Manager", "name": "ICT 1", "children":[
{"id": 4, "job": "ICT Assist", "name": "ICT 2", "children" : [
{"id": 5, "job": "ICT Junior", "name": "ICT 3"}
]}
]}
],
}]
是否有一個根節點(ManagerID = 0),其他所有分支都分支了。
我嘗試改寫其他問題的代碼,但無法生成此所需格式
我一直在使用的代碼如下,但這仍然重復了父節點
classes = [] #everyones id
for item in lst:
name = item['id']
if name not in classes:
classes.append(name)
treenodes = {}
root_node = None
for item in lst: # Create tree nodes
item['children'] = []
name = item['id']
treenodes[name] = item
parent = item['ManagerID']
if parent not in classes: # parent is root node, create
if parent not in treenodes:
node = {}
node['ManagerID'] = 0 #set manager to root
node['children'] = []
node['id'] = parent
root_node = node
treenodes[parent] = node
# Connect parents and children
for item in lst: # Create tree nodes
parent = item['ManagerID']
parent_node = treenodes[parent]
parent_node['children'].append(item)
output = treenodes
任何幫助,不勝感激。
這是用於構建層次結構的遞歸版本。
from pprint import pprint
def to_lookup(employees):
employee_lookup = dict()
for employee in employees:
if employee["id"] != employee["ManagerID"]:
manager_id = employee["ManagerID"]
children = employee_lookup.get(manager_id)
if not children:
children = employee_lookup[manager_id] = list()
children.append(employee.copy())
else:
manager = employee.copy()
return manager, employee_lookup
def build_hierarchy(manager, employee_lookup):
employees = employee_lookup.get(manager["id"], list())
for employee in employees:
build_hierarchy(employee, employee_lookup)
if employees:
manager['children'] = employees
return manager
employees = [
{"id": 0, "job": "CEO", "ManagerID": 0, "name": "John Smith"},
{"id": 1, "job": "Medical Manager", "ManagerID": 0, "name": "Medic 1"},
{"id": 2, "job": "Medical Assist", "ManagerID": 1, "name": "Medic 2"},
{"id": 3, "job": "ICT Manager", "ManagerID": 0, "name": "ICT 1"},
{"id": 4, "job": "ICT Assist", "ManagerID": 3, "name": "ICT 2"},
{"id": 5, "job": "ICT Junior", "ManagerID": 4, "name": "ICT 3"}
]
manager, employee_lookup = to_lookup(employees)
hierarchy = build_hierarchy(manager, employee_lookup)
pprint(hierarchy)
{'ManagerID': 0,
'children': [{'ManagerID': 0,
'children': [{'ManagerID': 1,
'id': 2,
'job': 'Medical Assist',
'name': 'Medic 2'}],
'id': 1,
'job': 'Medical Manager',
'name': 'Medic 1'},
{'ManagerID': 0,
'children': [{'ManagerID': 3,
'children': [{'ManagerID': 4,
'id': 5,
'job': 'ICT Junior',
'name': 'ICT 3'}],
'id': 4,
'job': 'ICT Assist',
'name': 'ICT 2'}],
'id': 3,
'job': 'ICT Manager',
'name': 'ICT 1'}],
'id': 0,
'job': 'CEO',
'name': 'John Smith'}
hierarchy_size = 2000000
employees = [
{"id": 0, "ManagerID": 0},
]
for idx in range(1, hierarchy_size):
manager_id = random.randint(0, idx - 1)
employees.append({"id": idx, "ManagerID": manager_id})
start = datetime.datetime.now()
manager, employee_lookup = to_lookup(employees)
hierarchy = build_hierarchy(manager, employee_lookup)
print(datetime.datetime.now() - start)
您的代碼實際上是有效的,但是您需要使用treenodes[0]
條目(CEO)。 treenodes
中其余的鍵值對僅用於簿記,以便輕松找到給定員工條目的給定經理。
如果您不能指望0
作為根節點的ID,那么您可以利用CEO被標記為自我管理這一事實; 根節點是管理員ID指向自己的ID的節點。 更為常見的情況是根節點根本沒有父ID。
您還將CEO添加到了自己的children
列表中(CEO的經理ID是他們自己的ID),因此您在樹中有一個遞歸引用。
您找到的代碼不是最清晰或最有效的。 我會從id
到復制的對象建立一個字典(這樣您的原始lst
字典就不會改變),然后遍歷該結構並將條目添加到其經理id條目中。 我正在使用“根節點自引用”規則(因此管理器ID等於他們自己的ID):
employees = {}
managers = set()
root_id = None
for emp in lst:
id, mid = emp['id'], emp['ManagerID']
# create a copy of emp, and add a "children" list
employees[id] = {**emp, 'children': []}
managers.add(mid)
if id == mid:
# the root of the tree references itself as the manager
root_id = id
# add empty manager entries for missing manager IDs, reporting to root ID.
for id in managers - employees.keys():
employees[id] = {
'id': id, 'ManagerID': root_id, 'children': [],
'job': None, 'name': None
}
for id, emp in employees.items():
manager = employees[emp.pop('ManagerID')]
if id != root_id: # don't add the root to anything
manager['children'].append(emp)
output = employees[root_id]
上面的代碼使用一組來跟蹤看到過哪些經理ID,因此您可以輕松添加丟失的經理條目(在這種情況下,報告給CEO)。
對於您的輸入,將產生:
{'id': 0, 'job': 'CEO', 'name': 'John Smith', 'children':
[{'id': 1, 'job': 'Medical Manager', 'name': 'Medic 1', 'children':
[{'id': 2, 'job': 'Medical Assist', 'name': 'Medic 2', 'children': []}],
},
{'id': 3, 'job': 'ICT Manager', 'name': 'ICT 1', 'children':
[{'id': 4, 'job': 'ICT Assist', 'name': 'ICT 2', 'children':
[{'id': 5, 'job': 'ICT Junior', 'name': 'ICT 3', 'children': []}]
}]
}]
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.