【树型问题】从一次不太合理的需求中引发一个思考题

需求:在部门管理中,如果某个管理员对父部门拥有权限,则对其部门及其以下任何部门都有权限;如果对某个部门对所有子部门拥有权限,则表示对其父部门拥有权限。

问题:现有一组含父部门节点和子部门节点的集合,根据已知的部门树形结构,要求消除含有父子关系节点,只保留最大权限的节点,例如:部门树形结构为[1, 1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2, 2.1, 2.2, 3, 4],部门1.1表示是1的子部门,1.2.1表示1.2的子部门,依此类推。
用例

部门树结构:[1, 1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2, 2.1, 2.2, 3, 4]
    egg1:(增加节点,减少子节点,用子节点替代父节点)
        管理者A权限:department_a=[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3]
        管理者B权限:department_b=[1.2.3, 2, 4]
        B操作步骤:给A增加权限[2,4],并去掉[1.2.3]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2, 4]
        A的最后结果应为:[1.1, 1.2.1, 1.2.2, 2, 4]
    egg2:(增加子节点补全,用父节点替代子节点)
        管理者A权限:department_a=[1.1, 1.2, 1.2.1, 1.2.2, 2, 4]
        管理者B权限:department_b=[1.2.3, 2, 4]
        B操作步骤:给A去掉权限[2,4],并增加 [1.2.3]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3]
        A的最后结果应为:[1]
    egg3:(减少子节点,增加子节点,用父节点替代子节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A去掉权限[2.2],并增加 [1.2.3]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 1.2.3, 4]
        A的最后结果应为:[1, 2.1, 4]
    egg4:(减少父节点,增加子节点,用父节点替代子节点)(?)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A去掉权限[2],并增加 [1.2.3]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 4]
        A的最后结果应为:[1, 4]
    egg5:(减少子节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A去掉权限[2.2]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 4]
        A的最后结果应为:[1.1, 1.2.1, 1.2.2, 4]
    egg6:(减少父节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A减少权限[2]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 4]
        A的最后结果应为:[1.1, 1.2.1, 1.2.2, 4]
    egg7:(增加子节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A增加权限[2.2]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2.2, 4]
        A的最后结果应为:[1, 4]
    egg8:(增加父节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A增加权限[2]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 4]
        A的最后结果应为:[1, 2, 4]
    egg9:(增加子节点,(无父节点),用父节点替代子节点)
        管理者A权限:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 2.2, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A增加权限[2.1]
        传参数:update_departments=[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2.1, 2.2, 4]
        A的最后结果应为:[1, 2, 4]
    egg10:(删除子节点)
        管理者A权限:update_departments=[1, 1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2, 2.1, 2.2, 3, 4]
        管理者B权限:[1.2.3, 2, 2.1, 2.2, 4]
        B操作步骤:给A删除权限[1.2.3]
        传参数:update_departments=[0, 1, 1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 3, 4]
        A的最后结果应为:[1.1, 1.2.1, 1.2.2, 2, 3, 4]
# coding:utf-8


def is_all_children(children, departments):
    """
    该节点是否含有全部子节点
    :param children:
    :param departments:
    :return:
    """

    res = []
    for n in departments:
        if n in children:
            res.append(n)

    if len(res) == 0:
        # 无子情况
        return -1

    return 0 if set(res) == set(children) else 1


def exists_parent(departments, p_c_dpts):
    """
    判断父子关系
    :param departments:
    :param p_c_dpts:
    :return:
    """

    for k, v in p_c_dpts.items():
        if k in departments and v in departments:
            return True

    return False


def get_merge_departments(departments):
    """
    将更新前后部门数据合并,组成新的部门集合
        特别注意:
        错误做法:1)包括全部子节点即删除子节点,这是错误的,必须从叶子节点开始检查。
         1
         1.1
          1.1.1
            1.1.1.1
            1.1.1.2
            1.1.1.3 (x)
          1.1.2
          1.1.3
         1.2
        说明:如果发现1.1的子节点都在,删除了即保留1.1,这是明显错误的,他只有(1.1.1.1, 1.1.1.2, 1.1.2, 1.1.3)
        2)不包括全部子节点即删除父节点,这是正确的。
        正确解法:先找到可删除的父节点进行删除,然后对包括全部子节点进行如下处理:(1)删除子节点,保留或增加父节点;
        (2)循环遍历,因为新增的父节点可能构成全部子节点中的一个节点,直到不同时存在父子关系的节点为止。

        是否存在父子关系?
            存在:1)处理不包括全部子节点的父节点立即删除(循环处理完)
                 2)包括全部子节点进行处理:删除子节点,保留或增加父节点(循环处理完)
            不存在:看兄弟节点能否组成一个某个父节点的全部子节点,回2)返回结果
    """

    # 保存父子关系,判断是否包含全部子节点
    p_dpts = {
             '1': ['1.1', '1.2'],
             '1.2': ['1.2.1', '1.2.2', '1.2.3'],
             '2': ['2.1', '2.2']
    }
    p_c_dpts = {
        '1.1': '1',
        '1.2': '1',
        '1.2.1': '1.2',
        '1.2.2': '1.2',
        '1.2.3': '1.2',
        '2.1': '2',
        '2.2': '2'
    }

    while True:
        if not exists_parent(departments, p_c_dpts):
            return departments

        # 处理不包括全部子节点的父节点立即删除(父子同时存在)
        flag = list()
        for index, up in enumerate(departments):
            if p_dpts.get(up) and is_all_children(p_dpts[up], departments) == 1:
                flag.append(up)

        # 进行删除
        for item in flag:
            departments.remove(item)

        flag = list()
        for index, up in enumerate(departments):
            if p_dpts.get(up) and is_all_children(p_dpts[up], departments) == 0:
                flag += p_dpts[up]

        # 进行删除
        for item in flag:
            departments.remove(item)

        # 兄弟节点能否合并
        flag = dict()
        for k, v in p_dpts.items():
            if not set(v).difference(set(departments)):
                flag[k] = v

        # 删除子节点,增加父节点
        for k, v in flag.items():
            departments.append(k)
            for i in v:
                departments.remove(i)


if __name__ == '__main__':

    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 2, 4]
    # A的最后结果应为:[1.1, 1.2.1, 1.2.2, 2, 4]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '2', '4']
    print("[1.1, 1.2.1, 1.2.2, 2, 4] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 1.2.3]
    # A的最后结果应为:[1]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '1.2.3']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 1.2.3]
    # A的最后结果应为:[1, 2.1]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '1.2.3', '2', '2.1']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 1.2.3] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 4]
    # A的最后结果应为:[1, 4]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '1.2.3', '4']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 4] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 4]
    # A的最后结果应为:[1.1, 1.2.1, 1.2.2, 4]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '4']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 4] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 4]
    # A的最后结果应为:[1, 2, 4]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '2', '2.1', '2.2', '4']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 4] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2.1, 2.2, 4]
    # A的最后结果应为:[1, 2, 4]
    update_departments = ['1.1', '1.2', '1.2.1', '1.2.2', '1.2.3', '2.1', '2.2', '4']
    print("[1.1, 1.2, 1.2.1, 1.2.2, 1.2.3, 2.1, 2.2, 4] = ", get_merge_departments(update_departments))
    # 传参数:update_departments = [1, 1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 4]
    # A的最后结果应为:[1.1, 1.2.1, 1.2.2, 2, 4]
    update_departments = ['1', '1.1', '1.2', '1.2.1', '1.2.2', '2', '2.1', '2.2', '4']
    print("[1, 1.1, 1.2, 1.2.1, 1.2.2, 2, 2.1, 2.2, 3, 4] = ", get_merge_departments(update_departments))
上一篇:关于网络空间资产安全解决方案,你需要了解的


下一篇:HVV信息收集工具Zfre_scan(优秀开源工具整合)