扁平化数组转换Tree数组

86 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

前言:

成功没有捷径但成长有路径

css必备场景。专注积累,每天记录一个知识点,老概念新理解,重点记录一下

每天梳理一个场景,知识点查漏补缺,充实满足。

正文

背景

最近复习,看到一个比较常用的算法,数组扁平的数据结构,需要把他转成树。这种需求在开发中经常使用到,应用场景比如说省市区的,树状图表之类的处理,不使用异步加载的情况,如果后端没有给树结构,而是一个扁平化的数据,我们需要把扁平数组转成级联的形式。不考虑性能问题,我们梳理几个最常用的方法。

扁平的数据是这样的

let arr = [
  { 
    dictCode: '370000', 
    dictName: '山东省', 
    dictParentCode: 'CN', 
    dictType: 1 },
  {
    dictCode: '370100',
    dictName: '济南市',
    dictParentCode: '370000',
    dictType: 1,
  },
  {
    dictCode: '370101 ',
    dictName: '市辖区',
    dictParentCode: '370100',
    dictType: 1,
  },
  {
    dictCode: '370200',
    dictName: '青岛市',
    dictParentCode: '370000',
    dictType: 1,
  }
];

要输出的结果

let arrTree = [
  {
    dictCode: '370000',
    dictName: '山东省',
    dictParentCode: 'CN',
    dictType: 1,
    children: [
      {
        dictCode: '370100',
        dictName: '济南市',
        dictParentCode: '370000',
        dictType: 1,
        children: [
          {
            dictCode: '370101 ',
            dictName: '市辖区',
            dictParentCode: '370100',
            dictType: 1,
          }
        ],
      },
      {
        dictCode: '370200',
        dictName: '青岛市',
        dictParentCode: '370000',
        dictType: 1,
      },
    ],
  },
];

方法

list to tree

扁平数组=>树结构数据

递归

递归主要思路,无脑执行,我们需要一个查子元素的方法,从rooId开始,不考虑性能一层一层遍历,获取所有的children,再递归调用该方法获取子children,直到查到所有。弊端就是性能问题

因为还要考虑到接口返回名称不一样,要做到方法通用, idKey, parentKey可以通过传值方式

/**
 *@param {arr: array 原数组数组, id:根节点id, idKey:节点名称,parentKey:父节点名称
 *@return {children:array子数组}
 */
function listToTree(arr, rootId, idKey = 'id', parentKey = 'pid') {
  const res = [];
  for (const item of arr) {
    if (item[parentKey] === rootId) {
      res.push({
        ...item,
        children: getChildren(arr, item[idKey], idKey, parentKey),
      });
    }
  }
  return res;
}
// 执行
listToTree(arr,'CN','dictCode','dictParentCode')

循环Map

利用对象的弱引用,相比递归性能上要好一些,创建一个map数据结构的字典,遍历找到数据修改它的children。下面这种写法,这只是一种思路, map的形式有很多种写法。

function listToTree(list = [], idKey, parentKey, rootId = 'CN') {
  const result = [];

  //创建一个map数据字典
  const dictionary = list.reduce((pre, cur) => {
    pre[cur[idKey]] = { ...cur, children: [] };
    return pre;
  }, {});

  list.forEach((item) => {
    //在字典中查找对应的数据
    const parent = dictionary[item[parentKey]];
    if (parent) {
      //修改它的children
      parent.children.push(dictionary[item[idKey]]);
    } else {
      //如果没找到就指定一个根节点
      result.push(dictionary[item[idKey]]);
    }
  });

  return result;
}
// 执行
listToTree(arr, 'dictCode', 'dictParentCode', 'CN')