#!/usr/bin/env python # -*- encoding: utf-8 -*- """ @Version: 1.0 @Python Version:3.6.6 @Author: ludq1 @Email: ludq1@chinaunicom.cn @date: 2023/04/07 11:40:00 @Description: """ import json from .my_stringutils import MyStringUtils class StructureUtils: r''' 结构变换便捷类 ''' DEFAULT_KEYNAME_ID = "id" DEFAULT_KEYNAME_PARENTID = "parentid" DEFAULT_KEYNAME_ISTOPNODE = "isTopNode" DEFAULT_KEYNAME_CHILDRENMAP = "childrenMap" DEFAULT_KEYNAME_CHILDREN = "children" DEFAULT_KEYNAME_SUBLIST = "sublist" DEFAULT_KEYNAME_NODELEVEL = "nodelevel" DEFAULT_KEYNAME_DESCENTDANTS = "descentdants" DEFAULT_KEYNAME_ANCESTORS = "ancestors" DEFAULT_KEYNAME_LEFTID = "leftId" DEFAULT_KEYNAME_RIGHTID = "rightId" @classmethod def transfer_dict_to_list(cls, a_dict: dict) -> list: r''' 将 map 转换回 list 例如 { "1":{ "id":1 }, "2":{ "id":2 }, "3":{ "id":3 } } 经过转换后为 [ {"id":1 }, {"id":2 }, {"id":3 } ] Args: a_dict: Returns: ''' if not a_dict: return [] if not isinstance(a_dict, dict): raise ValueError("a_dict不是字典") return [x for x in a_dict.values()] @classmethod def transfer_list_to_dict(cls, a_list: list, id_key: str = DEFAULT_KEYNAME_ID, parentid_key: str = DEFAULT_KEYNAME_PARENTID, topnode_parent_value: str = MyStringUtils.EMPTY, append_childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP) -> dict: r''' 将 list 转换为 以 id 为key,map为内容的map,
list中的map中的内容为 id,parentid的结构,
或只有id的结构(此时parentid_key参数传值为空字符串)
生成后在原有的map中增加 children key, 其对应一个map,包含各child id对应的map
parentid有值且不是 topNodeParentValue 时, 不会出现 topNodeParentValue 对应的map, 即这样的node也算作是顶级节点
生成后在原有的map中增加 isTopNode key, 表示该节点是否是顶级节点 例如: [ {"id":1,"parentid":None}, {"id":2,"parentid":222}, {"id":3,"parentid":1}, {"id":4,"parentid":2} ] 经过转换后为 { "1":{ "id":1, "parentid":None, "isTopNode":1, "childrenMap":{ "3":{"id":3,"parentid":1,"isTopNode":0} } }, "2":{ "id":2, "parentid":222, "isTopNode":1, "childrenMap":{ "4":{"id":4,"parentid":2,"isTopNode":0} } }, "3":{"id":3,"parentid":1,"isTopNode":0}, "4":{"id":4,"parentid":2,"isTopNode":0} } Args: a_list: id_key: parentid_key: topnode_parent_value: append_childrenmap_keyname: Returns: ''' if not a_list: return {} if not isinstance(a_list, (list, tuple)): raise ValueError("a_list不是list或tuple") result = {} id_key = cls._get_id_keyname(id_key) parentid_key = cls._get_parentid_keyname(parentid_key) topnode_parent_value = cls._get_topnode_parent_value(topnode_parent_value) append_childrenmap_keyname = cls._get_childrenmap_keyname(append_childrenmap_keyname) istopnode_keyname = cls._get_istopnode_keyname(None) all_id_list = cls._gen_all_id_values(a_list) # 遍历 a_list for tmp_dict in a_list: tmp_dict: dict # 取出 id 的值 id_value = tmp_dict.get(id_key) if id_value is None: raise ValueError('a_list中的字典中的{}的值不能为空'.format(id_key)) id_value = MyStringUtils.to_str(id_value) # 将自己加入到结果map中 # 取出 id对应的map self_map_in_result: dict = result.get(id_value) if self_map_in_result is not None: # 如果map中有自身, 说明之前有的map已经将其设置为自己的children了, 将children键取出, 放入tmpMap中 tmp_dict[append_childrenmap_keyname] = self_map_in_result.get(append_childrenmap_keyname) # 将id对应的map设置为自身 result[id_value] = tmp_dict if not MyStringUtils.is_empty(parentid_key): # 如果parentIdKeyName为空字符串,表示不需要处理parentId # 判断条件不为空, 表示需要处理 parentId # 取出parentid, 默认为空字符串, null等同于空字符串 parentid_val = MyStringUtils.to_str(tmp_dict.get(parentid_key)) # 将自己加入到parentId对应的map中的childrenMap中 if not (MyStringUtils.equals(topnode_parent_value, parentid_val) or MyStringUtils.is_empty( parentid_val) or not parentid_val in all_id_list): # 如果 parentId是空字符串或parentId的值是预设的顶级节点的parentId的值, 或者list中不包含 其父节点parentId, # 说明该节点是顶级节点 # 否则 说明该节点不是顶级节点, 需要设置自己是谁的子节点 # 设置自身是否是顶级节点的属性 tmp_dict[istopnode_keyname] = 0 parent_dict_in_result: dict = result.get(parentid_val) if parent_dict_in_result is None: parent_dict_in_result = {} result[parentid_val] = parent_dict_in_result # 从 parent_dict_in_result 中取出childrenMap childrenmap_in_parent: dict = parent_dict_in_result.get(append_childrenmap_keyname) if childrenmap_in_parent is None: childrenmap_in_parent = {} parent_dict_in_result[append_childrenmap_keyname] = childrenmap_in_parent childrenmap_in_parent[id_value] = tmp_dict else: tmp_dict[istopnode_keyname] = 1 return result @classmethod def transfer_list_to_dict_simple(cls, a_list: list, id_key: str = DEFAULT_KEYNAME_ID) -> dict: r''' 将 list 转换为 以 id 为key,map为内容的map,
例如: [ {"id":1, }, {"id":2 }, {"id":3 } ] 经过转换后为 { "1":{ "id":1 }, "2":{ "id":2 }, "3":{ "id":3 } } Args: a_list: id_key: Returns: ''' return cls.transfer_list_to_dict(a_list=a_list, id_key=id_key, parentid_key=MyStringUtils.EMPTY) @classmethod def gen_topnode_list(cls, a_dict: dict, istopnode_keyname: str = DEFAULT_KEYNAME_ISTOPNODE) -> list: r''' 将 以 id 为key,map为内容的map, map中的内容中包括 isTopNode key表示该map是否是顶级节点,以此提取所有的顶级节点的 id值的列表 例如 { "1":{ "id":1, "parentid":None, "isTopNode":1, "childrenMap":{ "3":{"id":3,"parentid":1,"isTopNode":0} } }, "2":{ "id":2, "parentid":222, "isTopNode":1, "childrenMap":{ "4":{"id":4,"parentid":2,"isTopNode":0} } }, "3":{"id":3,"parentid":1,"isTopNode":0}, "4":{"id":4,"parentid":2,"isTopNode":0} } 提取值为: ["1","2"] Args: a_dict: istopnode_keyname: Returns: ''' if not a_dict: return [] if not isinstance(a_dict, dict): raise ValueError('a_dict 不是 dict') result = [] for tmp_k, tmp_v in a_dict.items(): tmp_id = MyStringUtils.to_str(tmp_k) tmp_dict: dict = tmp_v if cls._is_topnode(tmp_dict, istopnode_keyname): result.append(tmp_id) return result @classmethod def gen_dict_only_contains_top_node(cls, a_dict: dict, istopnode_keyname: str = DEFAULT_KEYNAME_ISTOPNODE) -> dict: r''' 将 以 id 为key,map为内容的map,
map中的内容中包括 isTopNode key表示该map是否是顶级节点,以此构建一个新的map,
例如 { "1":{ "id":1, "parentid":None, "isTopNode":1, "childrenMap":{ "3":{"id":3,"parentid":1,"isTopNode":0} } }, "2":{ "id":2, "parentid":222, "isTopNode":1, "childrenMap":{ "4":{"id":4,"parentid":2,"isTopNode":0} } }, "3":{"id":3,"parentid":1,"isTopNode":0}, "4":{"id":4,"parentid":2,"isTopNode":0} } 经过转换后为 { "1":{ "id":1, "parentid":None, "isTopNode":1, "childrenMap":{ "3":{"id":3,"parentid":1,"isTopNode":0} } }, "2":{ "id":2, "parentid":222, "isTopNode":1, "childrenMap":{ "4":{"id":4,"parentid":2,"isTopNode":0} } } } Args: a_dict: istopnode_keyname: Returns: ''' if not a_dict: return {} if not isinstance(a_dict, dict): raise ValueError('a_dict 不是 dict') all_topnode_list = cls.gen_topnode_list(a_dict, istopnode_keyname=istopnode_keyname) return {tmp_node: a_dict.get(tmp_node) for tmp_node in all_topnode_list} @classmethod def transfer_list_to_dict_only_contains_top_node(cls, a_list: list, id_key: str = DEFAULT_KEYNAME_ID, parentid_key: str = DEFAULT_KEYNAME_PARENTID, topnode_parent_value: str = MyStringUtils.EMPTY, append_childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP) -> dict: r''' 将 list 转换为 以 id 为key,map为内容的map, list中的map中的内容为 id,parentid的结构, 或只有id的结构(此时parentIdKeyNameParam参数传值为空字符串) 生成后在原有的map中增加 children key, 其对应一个map,包含各child id对应的map parentid有值且不是 topNodeParentValue 时, 不会出现 topNodeParentValue 对应的map, 即这样的node也算作是顶级节点, 此函数返回的map中包含顶级节点,非顶级节点只出现在 children key中 例如 [ {"id":1,"parentid":None}, {"id":2,"parentid":222}, {"id":3,"parentid":1}, {"id":4,"parentid":2} ] 经过转换后为 { "1":{ "id":1, "parentid":None, "isTopNode":1, "childrenMap":{ "3":{"id":3,"parentid":1,"isTopNode":0} } }, "2":{ "id":2, "parentid":222, "isTopNode":1, "childrenMap":{ "4":{"id":4,"parentid":2,"isTopNode":0} } } } Args: a_list: id_key: parentid_key: topnode_parent_value: append_childrenmap_keyname: Returns: ''' return cls.gen_dict_only_contains_top_node( cls.transfer_list_to_dict(a_list, id_key=id_key, parentid_key=parentid_key, topnode_parent_value=topnode_parent_value, append_childrenmap_keyname=append_childrenmap_keyname)) @classmethod def grouplist_bykey(cls, a_list: list, groupby_keyname: str, append_sublist_keyname: str = None) -> list: r''' 将 list 聚合 例如 [ {"userid":1,"deptid":"1"}, {"userid":2,"deptid":"1"}, {"userid":3,"deptid":"2"}, {"userid":4,"deptid":"2"}, ] 经过聚合后为(可能包含冗余的key) [ { "userid":1,"deptid":"1", "sublist":[ {"userid":1,"deptid":"1"}, {"userid":2,"deptid":"1"} ] }, { "userid":3,"deptid":"2", "sublist":[ {"userid":3,"deptid":"2"}, {"userid":4,"deptid":"2"} ] } ] Args: a_list: groupby_keyname: append_sublist_keyname: Returns: ''' if not a_list: return [] if not isinstance(a_list, (list, tuple)): raise ValueError("a_list不是list或tuple") groupby_keyname = MyStringUtils.to_str(groupby_keyname) if MyStringUtils.is_empty(groupby_keyname): raise ValueError("groupByKeyName不能为空") append_sublist_keyname = cls._get_sublist_keyname(append_sublist_keyname) result_dict = {} for tmp_dict in a_list: tmp_dict: dict # 取出groupByKeyName对应的值 tmp_value_for_groupby_key = tmp_dict.get(groupby_keyname) if tmp_value_for_groupby_key is None: raise ValueError('{}对应的值不能为空'.format(groupby_keyname)) tmp_value_for_groupby_key = MyStringUtils.to_str(tmp_value_for_groupby_key) # 将自己加入到结果map中 # 取出 tmpValue对应的map self_map_in_result = result_dict.get(tmp_value_for_groupby_key) if self_map_in_result is None: # 如果resultMap 还没有 tmpValue对应的key,说明还没有将自己加入到resultMap中 self_map_in_result = tmp_dict.copy() result_dict[tmp_value_for_groupby_key] = self_map_in_result # 取出 selfMapInResult中的sublist对应的list tmp_sublist = self_map_in_result.get(append_sublist_keyname) if tmp_sublist is None: tmp_sublist = [] self_map_in_result[append_sublist_keyname] = tmp_sublist # 将自身加入到 sublist中去 tmp_sublist.append(tmp_dict) return cls.transfer_dict_to_list(result_dict) @classmethod def add_childrenlist_to_dict(cls, hierarchy_dict: dict, append_childrenlist_keyname: str = DEFAULT_KEYNAME_CHILDREN, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP) -> None: r''' 在具有层次结构的map 中增加children 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} }. "children":[ {"id":3,"parentid":1 } ] } Args: hierarchy_dict: append_childrenlist_keyname: childrenmap_keyname: Returns: ''' if not hierarchy_dict: return childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) append_childrenlist_keyname = cls._get_childrenlist_keyname(append_childrenlist_keyname) # 从map中取出childrenMap children_dict: dict = hierarchy_dict.get(childrenmap_keyname) if not children_dict: return else: # 否则遍历所有的children递归调用 children_list = [] for tmp_v in children_dict.values(): tmp_hierarchy_dict = tmp_v children_list.append(tmp_hierarchy_dict) cls.add_childrenlist_to_dict(tmp_hierarchy_dict, append_childrenlist_keyname=append_childrenlist_keyname, childrenmap_keyname=childrenmap_keyname) hierarchy_dict[append_childrenlist_keyname] = children_list return @classmethod def add_nodelevel_to_dict(cls, hierarchy_dict: dict, append_nodelevel_keyname: str = DEFAULT_KEYNAME_NODELEVEL, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, initial_level: int = 0) -> None: r''' 在具有层次结构的map 中增加nodelevel { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "nodelevel":0, "childrenMap":{ "3":{"id":3,"parentid":1,"nodelevel":1} } } Args: hierarchy_dict: append_nodelevel_keyname: childrenmap_keyname: initial_level: Returns: ''' if not hierarchy_dict: return childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) append_nodelevel_keyname = cls._get_nodelevel_keyname(append_nodelevel_keyname) # 在第一级map中增加初始level hierarchy_dict[append_nodelevel_keyname] = initial_level # 从map中取出childrenMap children_dict: dict = hierarchy_dict.get(childrenmap_keyname) if not children_dict: return else: # 否则遍历所有的children递归调用 for tmp_v in children_dict.values(): tmp_hierarchy_dict = tmp_v cls.add_nodelevel_to_dict(tmp_hierarchy_dict, append_nodelevel_keyname=append_nodelevel_keyname, childrenmap_keyname=childrenmap_keyname, initial_level=initial_level + 1) return @classmethod def add_descentdants_to_dict(cls, hierarchy_dict: dict, append_descentdants_keyname: str = DEFAULT_KEYNAME_DESCENTDANTS, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, id_key: str = DEFAULT_KEYNAME_ID) -> None: r''' 在具有层次结构的map 中增加 descentdants list 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "descentdants":["3"], "childrenMap":{ "3":{"id":3,"parentid":1} } } Args: hierarchy_dict: append_descentdants_keyname: childrenmap_keyname: id_key: Returns: ''' return cls._add_descentdants_to_dict_imp(hierarchy_dict=hierarchy_dict, append_descentdants_keyname=append_descentdants_keyname, childrenmap_keyname=childrenmap_keyname, id_key=id_key, to_append_descendants=None) @classmethod def _add_descentdants_to_dict_imp(cls, hierarchy_dict: dict, append_descentdants_keyname: str = DEFAULT_KEYNAME_DESCENTDANTS, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, id_key: str = DEFAULT_KEYNAME_ID, to_append_descendants: list = None) -> None: r''' 在具有层次结构的map 中增加 descentdants list 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "descentdants":["3"], "childrenMap":{ "3":{"id":3,"parentid":1} } } Args: hierarchy_dict: append_descentdants_keyname: childrenmap_keyname: id_key: to_append_descendants: Returns: ''' if not hierarchy_dict: return childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) append_descentdants_keyname = cls._get_descentdants_keyname(append_descentdants_keyname) id_key = cls._get_id_keyname(id_key) # 将自己的id追加到 toAppendList 中 id_val = hierarchy_dict.get(id_key) if id_val is None: raise ValueError('{}的值不能为空'.format(id_key)) id_val = MyStringUtils.to_str(id_val) if to_append_descendants: for tmp_list in to_append_descendants: tmp_list: list tmp_list.append(id_val) # 从map中取出childrenMap children_dict: dict = hierarchy_dict.get(childrenmap_keyname) if not children_dict: return else: # 否则遍历所有的children递归调用 descentdant_list = [] hierarchy_dict[append_descentdants_keyname] = descentdant_list to_append_descendants_new = None if to_append_descendants: to_append_descendants_new = to_append_descendants.copy() else: to_append_descendants_new = [] to_append_descendants_new.append(descentdant_list) for tmp_v in children_dict.values(): tmp_hierarchy_dict = tmp_v cls._add_descentdants_to_dict_imp(hierarchy_dict=tmp_hierarchy_dict, append_descentdants_keyname=append_descentdants_keyname, childrenmap_keyname=childrenmap_keyname, id_key=id_key, to_append_descendants=to_append_descendants_new) return @classmethod def add_ancestors_to_dict(cls, hierarchy_dict: dict, append_ancestors_keyname: str = DEFAULT_KEYNAME_ANCESTORS, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, id_key: str = DEFAULT_KEYNAME_ID) -> None: r''' 在具有层次结构的map 中增加 descentdants list 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1 , "ancestors":["1"]} } } Args: hierarchy_dict: append_ancestors_keyname: childrenmap_keyname: id_key: Returns: ''' return cls._add_ancestors_to_dict_imp(hierarchy_dict=hierarchy_dict, append_ancestors_keyname=append_ancestors_keyname, childrenmap_keyname=childrenmap_keyname, id_key=id_key, to_append_ancestors=None) @classmethod def _add_ancestors_to_dict_imp(cls, hierarchy_dict: dict, append_ancestors_keyname: str = DEFAULT_KEYNAME_ANCESTORS, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, id_key: str = DEFAULT_KEYNAME_ID, to_append_ancestors: list = None) -> None: r''' 在具有层次结构的map 中增加 descentdants list 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1 , "ancestors":["1"]} } } Args: hierarchy_dict: append_ancestors_keyname: childrenmap_keyname: id_key: to_append_ancestors: Returns: ''' if not hierarchy_dict: return childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) append_ancestors_keyname = cls._get_ancestors_keyname(append_ancestors_keyname) id_key = cls._get_id_keyname(id_key) # 设置自身的先祖id if to_append_ancestors: hierarchy_dict[append_ancestors_keyname] = to_append_ancestors # 从map中取出childrenMap children_dict: dict = hierarchy_dict.get(childrenmap_keyname) if not children_dict: return else: # 否则遍历所有的children递归调用 id_val = hierarchy_dict.get(id_key) if id_val is None: raise ValueError('{}的值不能为空'.format(id_key)) id_val = MyStringUtils.to_str(id_val) # 生成自己的要让后代追加的先祖id列表 to_append_ancestors_new = None if to_append_ancestors: to_append_ancestors_new = to_append_ancestors.copy() else: to_append_ancestors_new = [] to_append_ancestors_new.append(id_val) for tmp_v in children_dict.values(): tmp_hierarchy_dict = tmp_v cls._add_ancestors_to_dict_imp(hierarchy_dict=tmp_hierarchy_dict, append_ancestors_keyname=append_ancestors_keyname, childrenmap_keyname=childrenmap_keyname, id_key=id_key, to_append_ancestors=to_append_ancestors_new) return @classmethod def add_lrnode_to_dict(cls, hierarchy_dict: dict, append_leftid_keyname: str = DEFAULT_KEYNAME_LEFTID, append_rightid_keyname: str = DEFAULT_KEYNAME_RIGHTID, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, initial_leftid_value: int = 0) -> int: r''' 在具有层次结构的map 中增加 leftId,rightId 返回自身的右节点的值,用于递归 例如 { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} } } 经过转换后为 { "id":1, "parentid":None, "leftId":0, "rightId":3, "childrenMap":{ "3":{"id":3,"parentid":1,"leftId":1,"rightId":2 } } } Args: hierarchy_dict: append_leftid_keyname: append_rightid_keyname: childrenmap_keyname: initial_leftid_value: Returns: ''' if initial_leftid_value is None: initial_leftid_value = 0 if not hierarchy_dict: return initial_leftid_value - 1 childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) append_leftid_keyname = cls._get_leftid_keyname(append_leftid_keyname) append_rightid_keyname = cls._get_rightid_keyname(append_rightid_keyname) # 设置自身的leftId的值 hierarchy_dict[append_leftid_keyname] = initial_leftid_value # 预设返回值为左节点的值 + 1 ret_val = initial_leftid_value + 1 children_dict: dict = hierarchy_dict.get(childrenmap_keyname) if children_dict: # 如果子节点不为空,则遍历所有的children递归调用 for tmp_v in children_dict.values(): tmp_hierarchy_dict = tmp_v # 每个子节点的初始左节点就是预设的返回值 # 子节点返回的右节点的值+1就是新的预设的返回值 ret_val = cls.add_lrnode_to_dict(tmp_hierarchy_dict, append_leftid_keyname=append_leftid_keyname, append_rightid_keyname=append_rightid_keyname, childrenmap_keyname=childrenmap_keyname, initial_leftid_value=ret_val) + 1 # 将最后的返回值设置为右节点的值 hierarchy_dict[append_rightid_keyname] = ret_val return ret_val @classmethod def is_leaf_node(cls, a_dict: dict, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP) -> bool: r''' 判断 tmpMap是否是叶子节点, 根据 a_dict.get(childrenmap_keyname) 是否为空判断 Args: a_dict: childrenmap_keyname: Returns: ''' if not a_dict: return True childrenmap_keyname = cls._get_childrenmap_keyname(childrenmap_keyname) child_dict = a_dict.get(childrenmap_keyname) return child_dict is None or not child_dict @classmethod def remove_all_childrenmap(cls, a_list: list, childrenmap_keyname: str = DEFAULT_KEYNAME_CHILDRENMAP, childrenlist_keyname: str = DEFAULT_KEYNAME_CHILDREN) -> None: r''' 清理工作,移除所有的childrenMap 例如 [ { "id":1, "parentid":None, "childrenMap":{ "3":{"id":3,"parentid":1} }, "children":[ {"id":3,"parentid":1 } ] } ] 经过转换后为 [ { "id":1, "parentid":None, "children":[ {"id":3,"parentid":1 } ] } ] Args: a_list: childrenmap_keyname: childrenlist_keyname: Returns: ''' if not a_list: return # 遍历list for tmp_dict in a_list: tmp_dict: dict # 移除map中的 childrenMap tmp_dict.pop(cls._get_childrenmap_keyname(childrenmap_keyname), None) # 递归移除 list的children recursive_list = tmp_dict.get(cls._get_childrenlist_keyname(childrenlist_keyname)) cls.remove_all_childrenmap(a_list=recursive_list, childrenmap_keyname=childrenmap_keyname, childrenlist_keyname=childrenlist_keyname) return @classmethod def _is_topnode(cls, a_dict: dict, istopnode_keyname: str = DEFAULT_KEYNAME_ISTOPNODE) -> bool: r''' 判断 tmpMap是否是顶级节点 Args: a_dict: istopnode_keyname: Returns: ''' istopnode_keyname = cls._get_istopnode_keyname(istopnode_keyname) is_top_val = a_dict.get(istopnode_keyname) if is_top_val is None: raise ValueError("{}不存在,无法判断节点是否是顶级节点".format(istopnode_keyname)) return MyStringUtils.equals(is_top_val, "1") @classmethod def _get_str_value_with_default(cls, a_str: str, default: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 defaultValue Args: a_str: default: Returns: ''' if MyStringUtils.is_empty(a_str): return default else: return MyStringUtils.to_str(a_str) @classmethod def _get_id_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 id Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_ID) @classmethod def _get_parentid_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 parentid Args: a_str: Returns: ''' if a_str is None: return cls.DEFAULT_KEYNAME_PARENTID else: return MyStringUtils.to_str(a_str) @classmethod def _get_istopnode_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 isTopNode Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_ISTOPNODE) @classmethod def _get_topnode_parent_value(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 StringUtils.EMPTY Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, MyStringUtils.EMPTY) @classmethod def _get_childrenmap_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 childrenMap Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_CHILDRENMAP) @classmethod def _get_childrenlist_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 children Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_CHILDREN) @classmethod def _get_sublist_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 sublist Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_SUBLIST) @classmethod def _get_nodelevel_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 nodelevel Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_NODELEVEL) @classmethod def _get_descentdants_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 descentdants Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_DESCENTDANTS) @classmethod def _get_ancestors_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 ancestors Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_ANCESTORS) @classmethod def _get_leftid_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 leftId Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_LEFTID) @classmethod def _get_rightid_keyname(cls, a_str: str): r''' 如果aString不为None或EMPTY,返回aString,否则返回默认值 rightId Args: a_str: Returns: ''' return cls._get_str_value_with_default(a_str, cls.DEFAULT_KEYNAME_RIGHTID) @classmethod def _gen_all_id_values(cls, a_list: list, id_key: str = None) -> list: r''' 提取所有的id值列表
a_list 的内容应该是下面的这种结构, 每个列表项是一个dict, dict中包含id这个key,且该key对应的value必须不能为空 [ {"id":1,"parentid":None}, {"id":2,"parentid":222}, {"id":3,"parentid":1}, {"id":4,"parentid":2} ] Args: a_list: id_key: Returns: ''' if not a_list: return [] if not isinstance(a_list, (list, tuple)): raise ValueError('a_list不是list或tuple') id_key = cls._get_id_keyname(id_key) result = [] for tmp_dict in a_list: tmp_dict: dict tmp_val = tmp_dict.get(id_key) if tmp_val is None: raise ValueError('a_list中的字典中的{}的值不能为空'.format(id_key)) result.append(MyStringUtils.to_str(tmp_val)) return result @classmethod def do_replace_jsonobj_str(cls, a_dict: dict, keylist: list) -> dict: r''' 替换 a_dict 中的 keylist 对应的jsonObj字符串转换为 dict 对象
返回自身 Args: a_dict: keylist: Returns: ''' if not a_dict: return a_dict if isinstance(keylist, str): keylist = (keylist,) for tmp_key in keylist: # 尝试获取 tmp_ley 对应的值 tmp_val = a_dict.get(tmp_key) if tmp_val is None or isinstance(tmp_val, (list, tuple, dict)): continue # 将其转成字符串 tmp_val = MyStringUtils.to_str(tmp_val) # 尝试转成 dict 等对象 try: tmp_val = json.loads(tmp_val) a_dict[tmp_key] = tmp_val except: raise ValueError('{}对应的值不是json有效的json字符串'.format(tmp_key)) return a_dict @classmethod def do_replace_jsonobj_str_for_list(cls, a_list: list, keylist: list) -> list: r''' 替换 a_list 中的每个列表项中的 keylist 对应的jsonObj字符串转换为 dict 对象
返回自身 Args: a_list: keylist: Returns: ''' if not a_list: return list for tmp_dict in a_list: cls.do_replace_jsonobj_str(tmp_dict, keylist=keylist) return a_list @classmethod def do_deduplication(cls, a_list: list, key_for_check_duplicate: str) -> list: r''' 去重复,返回一个新的jsonarray,jsonarray包含的是jsonObject Args: a_dict: key_for_check_duplicate: Returns: ''' if not a_list: return [] result = [] existed_ids = [] for tmp_dict in a_list: tmp_dict: dict id_value = MyStringUtils.to_str(tmp_dict.get(key_for_check_duplicate)) if (not MyStringUtils.is_empty(id_value)) and id_value not in existed_ids: result.append(tmp_dict) existed_ids.append(id_value) return result @classmethod def do_preserve_key_for_dict(cls, a_dict: dict, keylist: list) -> dict: r''' 去掉jsonobject中多余的key,只保留指定的key 返回自身 Args: a_dict: keylist: Returns: ''' if not a_dict: return a_dict if isinstance(keylist, str): keylist = (keylist,) filter_keys = list(filter(lambda x: x in keylist, a_dict.keys())) if not filter_keys: raise ValueError("a_dict中不存在要保留的key") to_removed_keys = list(filter(lambda x: x not in filter_keys, a_dict.keys())) for tmp_key in to_removed_keys: a_dict.pop(tmp_key, None) return a_dict @classmethod def do_preserve_key_for_list(cls, a_list: list, keylist: list) -> list: r''' 替换 a_list 中的每个列表项中的 多余的key,只保留指定的key
返回自身 Args: a_list: keylist: Returns: ''' if not a_list: return list for tmp_dict in a_list: cls.do_preserve_key_for_dict(tmp_dict, keylist=keylist) return a_list @classmethod def do_rename_key_for_dict(cls, a_dict: dict, to_rename_kv: dict) -> dict: r''' 重命名jsonobj中的key
返回自身 Args: a_dict: keylist: Returns: ''' if not a_dict: return a_dict if not to_rename_kv: return a_dict for tmp_k, tmp_v in to_rename_kv.items(): if tmp_k in a_dict.keys(): tmp_v_in_dict_for_k = a_dict.pop(tmp_k) a_dict[tmp_v] = tmp_v_in_dict_for_k return a_dict @classmethod def do_rename_key_for_list(cls, a_list: list, to_rename_kv: dict) -> list: r''' a_list 中的每个列表项中的 重命名jsonobj中的key
返回自身 Args: a_list: to_rename_kv: Returns: ''' if not a_list: return list for tmp_dict in a_list: cls.do_rename_key_for_dict(tmp_dict, to_rename_kv=to_rename_kv) return a_list