我有items
个亲子关系。每个孩子都认识自己的父母,但父母不了解自己的孩子或孙子:
items = [
{'id': 1, 'parent': None},
{'id': 2, 'parent': 1},
{'id': 3, 'parent': 2},
{'id': 4, 'parent': None},
{'id': 5, 'parent': 4},
]
我正在尝试构建一个包含所有项目ID的字典,其中包含其所有子代,孙子等等的列表:
all_children_of_items = {
1: [2, 3], # 2 = child, 3 = grandchild
2: [3],
3: [],
4: [5],
5: [6]
}
我目前的做法只考虑孩子,而不考虑孙子:
all_children_of_items = {}
while True:
change = False
for item in items:
if item['id'] not in all_children_of_items:
all_children_of_items[item['id']] = []
if item['parent']:
if item['parent'] not in all_children_of_items:
all_children_of_items[item['parent']] = []
if item['id'] not in all_children_of_items[item['parent']]:
all_children_of_items[item['parent']].append(item['id'])
if not change:
break
当前结果:
{
1: [2],
2: [3],
3: [],
4: [5],
5: []
}
有什么主意吗?预先感谢!
答案 0 :(得分:1)
您可以尝试以下方法:
tree = {}
for item in items:
parent = item['id']
child = [it['id'] for it in items if it['parent'] == parent]
grandchild = [it['id'] for c in child for it in items if it['parent'] == c]
tree[parent] = [*child, *grandchild]
print(tree)
输出:
{1: [2, 3], 2: [3], 3: [], 4: [5], 5: []}
我看不到5
的孩子是6
,所以我的代码也没有。
可以对代码进行进一步优化,并针对更一般的用例进行修改。如果您认为合适,我会留给您。
编辑:
针对:
items = [{'id': 1, 'parent': None},
{'id': 2, 'parent': 1},
{'id': 3, 'parent': 2},
{'id': 4, 'parent': 3},
{'id': 5, 'parent': 4}]
代码:
def nepotism(parent):
lineage = []
def recurs(parent):
for item in items:
if item['parent'] == parent:
possible_parent = item['id']
lineage.append(possible_parent)
recurs(possible_parent)
recurs(parent)
return lineage
tree = dict([(item['id'], nepotism(item['id'])) for item in items])
print(tree)
输出:
{1: [2, 3, 4, 5], 2: [3, 4, 5], 3: [4, 5], 4: [5], 5: []}
答案 1 :(得分:1)
首先,您的while循环无用,因为您总是会在循环结束时中断。
要获得孙子孙,您需要复制
if item['parent']:
if item['parent'] not in all_children_of_items:
all_children_of_items[item['parent']] = []
if item['id'] not in all_children_of_items[item['parent']]:
all_children_of_items[item['parent']].append(item['id'])
检查自身内部以处理祖父母。如果要泛化代码以处理任何级别,则需要为要处理的每个其他级别继续在自身内部复制该块。
如果可能需要这种概括,那么递归方法将是最简单的方法,例如以下代码,其中还包括一个预处理步骤,以简化和优化后面的代码:
def getChildrenRecursive(items, maxLevel):
''' Returns a dict of item IDs and a list of their children up to maxLevel deep. '''
itemsByID = {}
result = {}
for item in items:
result[item['id']] = []
itemsByID[item['id']] = item
for item in items:
walkParents(result, item, itemsByID, item['id'], 1, maxLevel)
return result
def walkParents(result, item, items, idToAdd, level, maxLevel):
if level > maxLevel:
return
parent = item['parent']
if parent is None:
return
result[parent].append(idToAdd)
parentItem = items[parent]
walkParents(result, parentItem, items, idToAdd, level + 1, maxLevel)
请注意,该代码可以很容易地转换为非递归版本,因为它仅使用尾部调用,但我将其留给读者练习。
仅仅为了抚养孩子和孙子,就这样称呼:
items = [
{'id': 1, 'parent': None},
{'id': 2, 'parent': 1},
{'id': 3, 'parent': 2},
{'id': 4, 'parent': None},
{'id': 5, 'parent': 4},
]
getChildrenRecursive(items, 2) # Returns the result. The number is the maximum number of steps to walk.
答案 2 :(得分:1)
这是另一种解决方案:
items = [
{'id': 1, 'parent': None},
{'id': 2, 'parent': 1},
{'id': 3, 'parent': 2},
{'id': 4, 'parent': 3},
{'id': 5, 'parent': None},
]
families = {item['id']: [] for item in items}
def crawl_relations(relatives):
if len(relatives) and len(families[relatives[0]]) and families[relatives[0]][0] != relatives[-1]:
crawl_relations(families[relatives[0]])
relatives += families[relatives[0]]
for item in items:
if item['parent'] is not None:
families[item['parent']].append(item['id'])
for relatives in families.values():
crawl_relations(relatives)
print(families)
答案 3 :(得分:1)
您在这里:
parents_of_children = {item['id']: item['parent'] for item in items}
def find_ancestors(child: int) -> Tuple[int, List[int]]:
def _find_ancestors(_id: int, family: List[int]):
if not parents_of_children[_id]:
return child, family
else:
return _find_ancestors(parents_of_children[_id], family + [parents_of_children[_id]])
return _find_ancestors(child, [])
def find_descendents(id: int, ancestors: List[Tuple[int, List[int]]]) -> List[int]:
family_trees = [[child] + ancestors_of_child for child, ancestors_of_child in
ancestors if id in ancestors_of_child]
return [child for child in
takewhile(lambda i: i != id, max(family_trees) if family_trees else [])][::-1]
ancestors = [find_ancestors(child) for child in parents_of_children]
descendents = {id: find_descendents(id, ancestors) for id, _ in ancestors}
print(descendents)
答案 4 :(得分:0)
您可以尝试使用:
if not change:
continue
break
只会中断while
循环的迭代。