Как получить всех потомков определенного родителя в древовидной иерархии
суть проблемы: Имеем древовидную иерархию. Получаем ее в двух видах (на выбор):
ls = [[1, 'name1', 0], [2, 'name2', 39], [3, 'name3', 39], [4, 'name4', 39], [5, 'name5', 39], [6, 'name6', 1], [7, 'name7', 39], [9, 'name9', 1], [10, 'name10', 39], [11, 'name11', 10], [14, 'name14', 17], [15, 'name15', 2], [16, 'name16', 2], [17, 'name17', 10], [20, 'name20', 17], [21, 'name21', 11], [22, 'name22', 6], [23, 'name23', 0], [24, 'name24', 1], [25, 'name25', 7], [27, 'name27', 7], [29, 'name29', 9], [30, 'name30', 11], [31, 'name31', 11], [32, 'name32', 17], [33, 'name33', 9], [34, 'name34', 6], [36, 'name36', 9], [37, 'name37', 36], [38, 'name38', 36], [39, 'name39', 1], [40, 'name40', 9], [41, 'name41', 9], [42, 'name42', 41], [43, 'name43', 41], [44, 'name44', 9], [45, 'name45', 39], [46, 'name46', 45], [47, 'name47', 45], [48, 'name48', 36], [49, 'name49', 24], [50, 'name50', 24], [51, 'name51', 40], [52, 'name52', 40], [53, 'name53', 9], [54, 'name54', 53], [55, 'name55', 53], [58, 'name58', 1], [59, 'name59', 1], [60, 'name60', 14], [61, 'name61', 14], [62, 'name62', 9], [63, 'name63', 62]]
or
dt = {1: {'name': 'name1', 'parent_id': 0}, 2: {'name': 'name2', 'parent_id': 39}, 3: {'name': 'name3', 'parent_id': 39}, 4: {'name': 'name4', 'parent_id': 39}, 5: {'name': 'name5', 'parent_id': 39}, 6: {'name': 'name6', 'parent_id': 1}, 7: {'name': 'name7', 'parent_id': 39}, 9: {'name': 'name9', 'parent_id': 1}, 10: {'name': 'name10', 'parent_id': 39}, 11: {'name': 'name11', 'parent_id': 10}, 14: {'name': 'name14', 'parent_id': 17}, 15: {'name': 'name15', 'parent_id': 2}, 16: {'name': 'name16', 'parent_id': 2}, 17: {'name': 'name17', 'parent_id': 10}, 20: {'name': 'name20', 'parent_id': 17}, 21: {'name': 'name21', 'parent_id': 11}, 22: {'name': 'name22', 'parent_id': 6}, 23: {'name': 'name23', 'parent_id': 0}, 24: {'name': 'name24', 'parent_id': 1}, 25: {'name': 'name25', 'parent_id': 7}, 27: {'name': 'name27', 'parent_id': 7}, 29: {'name': 'name29', 'parent_id': 9}, 30: {'name': 'name30', 'parent_id': 11}, 31: {'name': 'name31', 'parent_id': 11}, 32: {'name': 'name32', 'parent_id': 17}, 33: {'name': 'name33', 'parent_id': 9}, 34: {'name': 'name34', 'parent_id': 6}, 36: {'name': 'name36', 'parent_id': 9}, 37: {'name': 'name37', 'parent_id': 36}, 38: {'name': 'name38', 'parent_id': 36}, 39: {'name': 'name39', 'parent_id': 1}, 40: {'name': 'name40', 'parent_id': 9}, 41: {'name': 'name41', 'parent_id': 9}, 42: {'name': 'name42', 'parent_id': 41}, 43: {'name': 'name43', 'parent_id': 41}, 44: {'name': 'name44', 'parent_id': 9}, 45: {'name': 'name45', 'parent_id': 39}, 46: {'name': 'name46', 'parent_id': 45}, 47: {'name': 'name47', 'parent_id': 45}, 48: {'name': 'name48', 'parent_id': 36}, 49: {'name': 'name49', 'parent_id': 24}, 50: {'name': 'name50', 'parent_id': 24}, 51: {'name': 'name51', 'parent_id': 40}, 52: {'name': 'name52', 'parent_id': 40}, 53: {'name': 'name53', 'parent_id': 9}, 54: {'name': 'name54', 'parent_id': 53}, 55: {'name': 'name55', 'parent_id': 53}, 58: {'name': 'name58', 'parent_id': 1}, 59: {'name': 'name59', 'parent_id': 1}, 60: {'name': 'name60', 'parent_id': 14}, 61: {'name': 'name61', 'parent_id': 14}, 62: {'name': 'name62', 'parent_id': 9}, 63: {'name': 'name63', 'parent_id': 62}}
Необходимо собрать всех потомков переданного родителя, например: parent_id = 10. Тогда вывод должен быть: ['name11', 'name17', 'name14', 'name20', 'name32', 'name60', 'name61', 'name21', 'name30', 'name31']
Изначально задача казалось весьма тривиальной и я сделал так: example_ls = [[row[1], row[0]] for row in ls if row[2] == department_id] что позволило получить только детей. Дальше через цикл я смог получить лишь 50% потомков.
Тогда я пошел другим путем и попробовал сделать рекурсию:
def recursion(ls, dep_true, department_id):
print(dep_true)
ind = [(n, row.index(department_id)) for n, row in enumerate(ls) if department_id == row[2]]
if ind:
children = []
for row in ind:
dep_true.append(ls[row[0]][1])
children.append(ls[row[0]][0])
# print(dep_true, set(children))
for row in set(children):
# print(row)
return recursion(ls, dep_true, row)
else:
return dep_true
Но из-за return recursion(ls, full_children, row) цикл становится бесполезным и я опять получаю 50% данных. Если убрать этот кусок кода, то на выходе я получаю None, а сама функция наполняет массив всеми 100% данных.
Возможно, что я застрял на чем-то очевидном или глупом. Буду рад помощи, заранее спасибо!
Ответы (2 шт):
data = {1: {'name': 'name1', 'parent_id': 0}, 2: {'name': 'name2', 'parent_id': 39}, 3: {'name': 'name3', 'parent_id': 39}, 4: {'name': 'name4', 'parent_id': 39}, 5: {'name': 'name5', 'parent_id': 39}, 6: {'name': 'name6', 'parent_id': 1}, 7: {'name': 'name7', 'parent_id': 39}, 9: {'name': 'name9', 'parent_id': 1}, 10: {'name': 'name10', 'parent_id': 39}, 11: {'name': 'name11', 'parent_id': 10}, 14: {'name': 'name14', 'parent_id': 17}, 15: {'name': 'name15', 'parent_id': 2}, 16: {'name': 'name16', 'parent_id': 2}, 17: {'name': 'name17', 'parent_id': 10}, 20: {'name': 'name20', 'parent_id': 17}, 21: {'name': 'name21', 'parent_id': 11}, 22: {'name': 'name22', 'parent_id': 6}, 23: {'name': 'name23', 'parent_id': 0}, 24: {'name': 'name24', 'parent_id': 1}, 25: {'name': 'name25', 'parent_id': 7}, 27: {'name': 'name27', 'parent_id': 7}, 29: {'name': 'name29', 'parent_id': 9}, 30: {'name': 'name30', 'parent_id': 11}, 31: {'name': 'name31', 'parent_id': 11}, 32: {'name': 'name32', 'parent_id': 17}, 33: {'name': 'name33', 'parent_id': 9}, 34: {'name': 'name34', 'parent_id': 6}, 36: {'name': 'name36', 'parent_id': 9}, 37: {'name': 'name37', 'parent_id': 36}, 38: {'name': 'name38', 'parent_id': 36}, 39: {'name': 'name39', 'parent_id': 1}, 40: {'name': 'name40', 'parent_id': 9}, 41: {'name': 'name41', 'parent_id': 9}, 42: {'name': 'name42', 'parent_id': 41}, 43: {'name': 'name43', 'parent_id': 41}, 44: {'name': 'name44', 'parent_id': 9}, 45: {'name': 'name45', 'parent_id': 39}, 46: {'name': 'name46', 'parent_id': 45}, 47: {'name': 'name47', 'parent_id': 45}, 48: {'name': 'name48', 'parent_id': 36}, 49: {'name': 'name49', 'parent_id': 24}, 50: {'name': 'name50', 'parent_id': 24}, 51: {'name': 'name51', 'parent_id': 40}, 52: {'name': 'name52', 'parent_id': 40}, 53: {'name': 'name53', 'parent_id': 9}, 54: {'name': 'name54', 'parent_id': 53}, 55: {'name': 'name55', 'parent_id': 53}, 58: {'name': 'name58', 'parent_id': 1}, 59: {'name': 'name59', 'parent_id': 1}, 60: {'name': 'name60', 'parent_id': 14}, 61: {'name': 'name61', 'parent_id': 14}, 62: {'name': 'name62', 'parent_id': 9}, 63: {'name': 'name63', 'parent_id': 62}}
Можно так:
children = {}
for k, v in d.items():
if v['parent_id'] == 10:
children.update({k: v})
или
children = {k: v for k, v in dt.items() if v['parent_id'] == 10}
или
children = dict((k, v) for k, v in dt.items() if v['parent_id'] == 10)
новый словарь children содержит только записи с parent_id, равными 10:
>>> children
{
11: {'name': 'name11', 'parent_id': 10},
17: {'name': 'name17', 'parent_id': 10}
}
Всё-равно не очень понял задачу, но попробуйте этот кусок:
for row in set(children):
# print(row)
return recursion(ls, dep_true, row)
else:
return dep_true
Поменять на этот:
for row in set(children):
# print(row)
recursion(ls, dep_true, row)
return dep_true
Т.е. не выходить сразу из цикла на первой же итерации, а пройти по циклу полностью, накопить элементы в dep_true и потом уже выйти из функции по return.