算法 一维数组转化为多维数组(已知id、父id和目录级别)

342 阅读2分钟

算法 一维数组转化为多维数组(已知id、父id和目录级别)

开发时可能会遇到这样的问题:

前端需要渲染多层级的目录列表,但是后端返回的却是一个扁平化的数组

返回数据如以下情况(已删除敏感数据):

  • LEVEL:目录级别
  • NODE_ID:当前节点的标识
  • P_NODE_ID:父节点的标识
const list = [  
    {  
        LEVEL: 1,  
        NODE_ID: 294,  
        P_NODE_ID: 254,  
    },  
    {  
        LEVEL: 1,    
        NODE_ID: 293,  
        P_NODE_ID: 254,  
    },  
    {  
        LEVEL: 2,   
        NODE_ID: 299,  
        P_NODE_ID: 294,   
    },  
    {   
        LEVEL: 3,    
        NODE_ID: 389,   
        P_NODE_ID: 299,  
    },  
    {   
        LEVEL: 2,    
        NODE_ID: 354,    
        P_NODE_ID: 293,  
    },  
    {   
        LEVEL: 3,    
        NODE_ID: 342,   
        P_NODE_ID: 354,   
    },  
];

如果后端无法修改或者打死不改,那么只能由前端进行处理

解决思路与方法

看到这种问题,脑中的第一个想法就是暴力破解:

image.png

但是每次查找父节点,我们一般会调用find方法,但是find方法在查找的过程中会遍历整个数组直到找到符合条件的元素数据过大,那么总体消耗的时间就会过长


上面的方法耗时长是因为每一个元素都需要找到自己的父节点,然后添加到父节点,一个父节点下可能有多个子节点,那么我们可以将上面的步骤进行反转

  1. 将同父节点的元素添加到数组中
  2. 查找关系,将元素一并加入

同父节点的元素有一个相同的点——P_NODE_ID(父节点标识相同),那么我们可以使用Map或者对象进行存储

const map = new Map();
let res = []; // 存放最终结果

list.forEach((val) => {
    let pid = val.P_NODE_ID; // 获取到父节点id
    if (map.has(pid)) { // map中存在pid,表示该元素存在同父节的元素
      map.set(pid, map.get(pid).push(val));
    } else if (val.LEVEL === 1) {
      // 第一层级不需要记录
      res.push(val);
    }else { // map中不存在pid,则需要进行初始化
      map.set(pid, [val]);
    }
});

存储完,接下来我们需要查找关系:

  // 根据id和map进行查找
  function findChildren(val, map) {
    const children = map.get(val.NODE_CODE) || [];
    children.map((val) => findChildren(val, map)); // 递归查找
    val.children = children;
    return val;
  }
  
  res = res.map((val) => {
    return findChildren(val, map);
  });

完整代码

function fn(list) {
  const map = new Map();
  let res = [];
  // 记录
  list.forEach((val) => {
    let pid = val.P_NODE_CODE;
    if (map.has(pid)) {
      map.set(pid, map.get(pid).push(val));
    } else if (val.LEVEL === 1) {
      // 第一层级不需要记录
      res.push(val);
    } else {
      map.set(pid, [val]);
    }
  });

  // 根据id和map进行查找
  function findChildren(val, map) {
    const children = map.get(val.NODE_CODE) || [];
    children.map((val) => findChildren(val, map));
    val.children = children;
    return val;
  }

  return res.map((val) => {
    return findChildren(val, map);
  });
}