树形结构转列表

  1. /*
  2. 题目描述:
  3. [
  4. {
  5. id: 1,
  6. text: '节点1',
  7. parentId: 0,
  8. children: [
  9. {
  10. id:2,
  11. text: '节点1_1',
  12. parentId:1
  13. }
  14. ]
  15. }
  16. ]
  17. 转成
  18. [
  19. {
  20. id: 1,
  21. text: '节点1',
  22. parentId: 0 //这里用0表示为顶级节点
  23. },
  24. {
  25. id: 2,
  26. text: '节点1_1',
  27. parentId: 1 //通过这个字段来确定子父级
  28. }
  29. ...
  30. ]
  31. */
  32. function tree2List(treeData) {
  33. let result = []
  34. const dfs = data => {
  35. data.forEach(item => {
  36. result.push(item)
  37. if(item.children) {
  38. dfs(item.children)
  39. delete item.children
  40. }
  41. })
  42. }
  43. dfs(treeData)
  44. return result
  45. }
  46. var treeData = [
  47. {
  48. id: 1,
  49. text: '节点1',
  50. parentId: 0,
  51. children: [
  52. {
  53. id:2,
  54. text: '节点1_1',
  55. parentId:1
  56. }
  57. ]
  58. },
  59. {
  60. id: 2,
  61. text: '节点2',
  62. parentId: 0,
  63. children: []
  64. }
  65. ]
  66. tree2List(treeData)
  1. export function flattenDeep<T extends {children: T[];}>(list: T[], newList?: T[]): T[] {
  2. if (!list.length) return list;
  3. if (!newList) newList = [];
  4. for (let index = 0; index < list.length; index++) {
  5. const item = list[index];
  6. // 拷贝 item ;目的:删除 copyItem 的 children 推送到 newList 中,最终返回的 newList 中就没有了 children 字段
  7. const itemDeleteChild = JSON.parse(JSON.stringify(item));
  8. if (Reflect.deleteProperty(itemDeleteChild, "children")) {
  9. newList.push(itemDeleteChild);
  10. }
  11. if (item.children && !!item.children.length) {
  12. flattenDeep(item.children, newList);
  13. }
  14. }
  15. return newList;
  16. }
  1. type TMap = Map<
  2. number,
  3. {
  4. parentId: number;
  5. label: string;
  6. }
  7. >;
  8. export function flattenDeepToMap<
  9. T extends {
  10. children: T[];
  11. }
  12. >(list: T[], newList?: T[], tempMap?: TMap): TMap {
  13. if (!list.length) return new Map();
  14. if (!newList) newList = [];
  15. if (!tempMap || !tempMap.size) tempMap = new Map();
  16. for (let index = 0; index < list.length; index++) {
  17. const item = list[index];
  18. // 拷贝 item ;目的:删除 copyItem 的 children 推送到 newList 中,最终返回的 newList 中就没有了 children 字段
  19. const itemDeleteChild = JSON.parse(JSON.stringify(item));
  20. if (Reflect.deleteProperty(itemDeleteChild, "children")) {
  21. tempMap.set(itemDeleteChild.id, {
  22. parentId: itemDeleteChild.parentId,
  23. label: itemDeleteChild.name,
  24. });
  25. newList.push(itemDeleteChild);
  26. }
  27. if (item.children && !!item.children.length) {
  28. flattenDeepToMap(item.children, newList);
  29. }
  30. }
  31. console.log(`tempMap---->`, tempMap);
  32. return tempMap;
  33. }

列表转树形结构

  1. let arr = [
  2. { id: 1, name: "部门1", parentId: 0 },
  3. { id: 2, name: "部门2", parentId: 1 },
  4. { id: 3, name: "部门3", parentId: 1 },
  5. { id: 4, name: "部门4", parentId: 3 },
  6. { id: 5, name: "部门5", parentId: 1 },
  7. ];
  8. /* 方法一:递归遍历查找(不推荐)时间复杂度为O(2^n) */
  9. function buildTree(list: any[], parentId: number, result: any[]) {
  10. for (let item of list) {
  11. if (item.parentId === parentId) {
  12. const newItem = { ...item, children: [] };
  13. result.push(newItem);
  14. buildTree(list, item.id, newItem.children); // 重要,注意入参是:需要遍历的list , 需要挂载的当前ID , 需要挂载的当前 children
  15. }
  16. }
  17. }
  18. function FlattenToTree({ list, rootId }: { list: any[]; rootId: number }) {
  19. const result: any[] = [];
  20. buildTree(list, rootId, result);
  21. return result;
  22. }
  23. // console.log(JSON.stringify(FlattenToTree({ list: arr, rootId: 0 })))
  1. /* 法二:不用递归,先把数据转成 Map 存储,之后遍历的同时借用 对象的引用,直接从 Map 中找到对应的数据做存储 */
  2. /* 两次循环,时间复杂度 O(2n),需要 Map 把数据存储起来,空间复杂度 O(n) */
  3. /* 此方法会过滤掉当个无关联节点,只是将关联节点进行了构建。如:{id: 8, name: '部门4', parentId: 90} id/parentId 都与其他节点无关联 */
  4. function FlattenToTree_01({ list, rootId }: { list: any[]; rootId: number }) {
  5. const result: any[] = [];
  6. let tempMap: any = {}; // 作用:将所有可能出现的节点汇总,方便按层级进行挂载
  7. for (const item of list) {
  8. tempMap[item.id] = { ...item, children: [] };
  9. }
  10. for (const iterator of list) {
  11. const id = iterator.id;
  12. const parentId = iterator.parentId;
  13. const treeItem = tempMap[id]; // 重要,当找到根节点时要 push 到 result 中
  14. if (parentId === rootId) {
  15. result.push(treeItem);
  16. } else {
  17. // 做这一步判断的目的是什么???
  18. if (!tempMap[parentId]) {
  19. tempMap[parentId] = {
  20. children: [],
  21. };
  22. }
  23. tempMap[parentId].children.push(treeItem);
  24. }
  25. }
  26. return result;
  27. }
  28. // console.log(JSON.stringify(FlattenToTree_01({ list: arr, rootId: 0 })))
  1. /* 法三:不用递归。
  2. 思路:
  3. 数据转成 Map 存储,之后遍历的同时借助 对象的引用,直接从 Map 中找到对应的数据做存储。
  4. 与方法二不同点在于,遍历时即做 Map 存储,
  5. */
  6. function FlattenToTree_02({ list, rootId }: { list: any[]; rootId: number }) {
  7. const result: any[] = [];
  8. let tempMap: any = {}; // 作用:将所有可能出现的节点汇总,方便按层级进行挂载
  9. for (const item of list) {
  10. const id = item.id;
  11. const parentId = item.parentId;
  12. if (!tempMap[id]) {
  13. tempMap[id] = {
  14. children: [],
  15. };
  16. }
  17. tempMap[id] = {
  18. ...item,
  19. children: tempMap[id]["children"],
  20. };
  21. const treeItem = tempMap[id];
  22. if (parentId === rootId) {
  23. result.push(treeItem);
  24. } else {
  25. if (!tempMap[parentId]) {
  26. tempMap[parentId] = {
  27. children: [],
  28. };
  29. }
  30. tempMap[parentId].children.push(treeItem);
  31. }
  32. }
  33. return result;
  34. }
  35. // console.log(JSON.stringify(FlattenToTree_02({ list: arr, rootId: 0 })))
  1. const otherParams = {
  2. idName: "id",
  3. parentName: "parentId",
  4. childName: "children",
  5. };
  6. interface IGenerateTree {
  7. list: any[];
  8. rootId: number | string;
  9. params?: typeof otherParams;
  10. }
  11. function generateTree({ list, rootId, params = otherParams }: IGenerateTree) {
  12. const { idName, parentName, childName } = params;
  13. const result: any[] = []; // 结果
  14. let tempMap: any = {}; // 暂存数据,以 id 为 key 的映射关系
  15. for (const item of list) {
  16. const id = item[idName];
  17. const parentId = item[parentName];
  18. if (!tempMap[id]) {
  19. tempMap[id] = {
  20. [childName]: [],
  21. };
  22. }
  23. tempMap[id] = {
  24. ...item,
  25. [childName]: tempMap[id][childName],
  26. };
  27. const treeItem = tempMap[id]; // 找到映射关系哪一项(注意这里是引用)
  28. if (parentId === rootId) {
  29. // 已经找到根元素,将映射结果放进结果集中
  30. result.push(treeItem);
  31. } else {
  32. if (!tempMap[parentId]) {
  33. tempMap[parentId][childName] = [];
  34. }
  35. tempMap[parentId][childName].push(treeItem);
  36. }
  37. }
  38. return result;
  39. }
  40. console.log(JSON.stringify(generateTree({ list: arr, rootId: 0 })));