Python树形结构操作

Python | 树形数据 | 递归

Posted by luoruiqing on July 13, 2022

工作开发中遇到人员管理或者菜单管理等需求时,会遇到树形数据操作的问题,这里提供两个通用的工具,用于生成对应结构.

平转树

1
2
3
4
5
6
7
8
9
#
def lto_tree(items, ckey='children', fkey='father_id', key='id'):
    ''' 平转树 (! 注意这里修改原对象, 请深拷贝或避免反复调用) '''
    for item in items:
        item.setdefault(ckey, [])
        father_id = item.get(fkey)
        father = father_id and next((father for father in items if father[key] == father_id), None)  # 找爸爸
        father and father.setdefault(ckey, []).append(item)
    return [item for item in items if not item.get(fkey)]

参数解释

  • ckey : 子节点的名称
  • fkey : 本节点对应的父节点的主键
  • key : 本节点的主键

调用方式

1
2
3
4
5
6
7
8
9
10
11
12
# 常规
dicts = [{"pk":1}, {"pk":2, "fpk":1}, {"pk":3, "fpk":2}]
combination_level(dicts, ckey="child", fkey="fpk", key="pk")
# [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}]}]
combination_level(dicts, ckey="child", fkey="fpk", key="pk") # 调用第二次
# [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}, {'pk': 3, 'fpk': 2, 'child': []}]}, {'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}, {'pk': 3, 'fpk': 2, 'child': []}]}]}]
# 拷贝
import copy
combination_level(copy.deepcopy(dicts), ckey="child", fkey="fpk", key="pk")
# [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}]}]
combination_level(copy.deepcopy(dicts), ckey="child", fkey="fpk", key="pk")
# [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}]}]

树转平

下探方法

1
2
3
4
5
def tree_callback(leafs, callback=None, ckey='children', root=None, level=0):
    ''' 下钻寻找节点 '''
    for leaf in leafs:
        callback(leaf, root, level + 1)  # 调用方法
        tree_callback(leaf.get(ckey, []), callback=callback, ckey=ckey, root=leaf, level=level + 1)

参数解释

  • leafs : 传入根节点(多个),如果单根可以套层列表 tree_callback([root], …)
  • ckey : 子节点的键名称
  • callback : 回掉方法
    • leaf : 当前节点
    • root : 当前节点的父节点
    • level : 当前节点所属的层级(1开始)

树转平操作

1
2
3
4
5
tree = [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}]}]
flat = []
tree_callback(tree, lambda leaf, *_: flat.append(leaf), ckey='child')
print(flat)
# [{'pk': 1, 'child': [{'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}]}, {'pk': 2, 'fpk': 1, 'child': [{'pk': 3, 'fpk': 2, 'child': []}]}, {'pk': 3, 'fpk': 2, 'child': []}]

通过上面两个方法就可以平树互转,下探方法可以分层级操作,分根操作,分页操作等等。