数组对象转成树,往树里添加叶子节点

有两个文件,文件1的数据是标签类目数据,有四列,cateId 是类目 id,cateName 是类目名字,catePId 是类目的父类目(一级类目为Null),isLeaf 是否是叶子类目,列分隔符是逗号;

文件2的数据是标签数据,有三列,tagId 是 标签 id,tagName 是标签名字,cateId 是标签所属的叶子类目,列分隔符是逗号

读取这两个文件,然后输出标签类目树结构

如下所示:

// [
//   {
//     id: '', // 类目 ID
//     name: '', // 类目名
//     list: [
//       {
//         id: '', // 类目 ID
//         name: '', // 类目名
//         list: [
//           {
//             tagId: '', // 标签 ID, 最后一层是标签数据
//             tagName: '' // 标签名
//           }
//         ]
//       }
//     ]
//   } // 一个一级类目
    ...
// ]
let wenjian1 = [
  {
    cateId: '1-1-1',
    cageName: '余杭区',
    catePId: '1-1',
    isLeaf: true
  },
  {
    cateId: '1-1-2',
    cageName: '西湖区',
    catePId: '1-1',
    isLeaf: true
  },
  {
    cateId: '1-1',
    cageName: '杭州',
    catePId: null,
    isLeaf: false
  },
  {
    cateId: '1-2',
    cageName: '金华',
    catePId: null,
    isLeaf: false
  }
]

let wenjian2 = [
  {
    tagId: 'abcd',
    tagName: '小王',
    cateId: '1-1-1'
  },
  {
    tagId: 'efgh',
    tagName: '小明',
    cateId: '1-1-2'
  },
  {
    tagId: 'xl',
    tagName: '小张',
    cateId: '1-1-1'
  }
]

let result = []

function xunhuan(data) {
  let result = [];              
  let obj = {}              
  data.forEach(item => {                 
    obj[item.cateId] = Object.assign(item, obj[item.cateId] || {}); 
    if (item.catePId) {                    
       let parent = obj[item.catePId] || {};        
       parent.list = parent.list || [];                     
       parent.list.push(item);                
       obj[item.catePId] = parent;                
    } else {                    
       result.push(obj[item.cateId])              
    }           
  })   
  console.log(result)  
  return result;
}

let wenjian1Result = xunhuan(wenjian1)
function digui(data) {
  if(data && data.length) {
    for(let item of data) {
      if(item.isLeaf) {
        let dd = wenjian2.filter(i => {
          if(i.cateId === item.cateId) {
            return i
          }
        })
        item.list = [].concat(dd) 
      } else {
        digui(item.list)
      }
    }
  }
}

digui(wenjian1Result)

console.log(wenjian1Result)

粗略实现了下,复杂度处理的不优,请朋友们指教

阅读 2k
3 个回答

数据有改动,叶子节点对应 isLeaf =true才查找 wenjian2 数据
image.png

let wenjian1 = [
  {
    cateId: '1-1-1',
    cageName: '余杭区',
    catePId: '1-1',
    isLeaf: true
  },
  {
    cateId: '1-1-2',
    cageName: '西湖区',
    catePId: '1-1',
    isLeaf: true
  },
  {
    cateId: '1-1',
    cageName: '杭州',
    catePId: null,
    isLeaf: false
  },
  {
    cateId: '1-2',
    cageName: '金华',
    catePId: null,
    isLeaf: false
  }
]
let wenjian2 = [
  {
    tagId: 'abcd',
    tagName: '小王',
    cateId: '1-1-1'
  },
  {
    tagId: 'efgh',
    tagName: '小明',
    cateId: '1-1-2'
  },
  {
    tagId: 'xl',
    tagName: '小张',
    cateId: '1-1-1'
  }
]
let toTree = (list,leafList,catePId=null)=>{
    return list.reduce((acc,cur)=>{
        // 根据父ID 获取节点
        if(catePId == cur.catePId){
            acc.push({
                id: cur.cateId, // 类目 ID
                name: cur.cageName, // 类目名
                list: cur.isLeaf ? leafList.filter(item=>item.cateId === cur.cateId) : toTree(list, leafList, cur.cateId) //叶子节点归并叶子列表数据,非叶子节点递归获取子节点
            })
            
        }
        return acc;
    },[])
}
toTree(wenjian1,wenjian2,null)
function list2tree(cages, tags) {
    const root = {
        cateId: "1",
        cageName: "浙江",
        catePId: null,
        isLeaf: false,
        list: []
    };
    const cageMap = new Map, tagMap = {};
    const length = Math.max(cages.length, tags.length);
    for (let i = 0; i < length; ++i) {
        const cage = cages[i], tag = tags[i];
        if (cage) cageMap.set(cage.cateId, { ...cage });
        if (tag) tagMap[tag.cateId] = [...(tagMap[tag.cateId] ?? []), tag];
    }
    for (const [cateId, cage] of cageMap) {
        if (cage.isLeaf) cage.list = tagMap[cateId];
        const parent = cageMap.get(cage.catePId) ?? root;
        parent.list = [...(parent.list ?? []), cage];
    }
    return root.list;
}
console.dir(list2tree(wenjian1, wenjian2));
// 第一步,建立 ID-NODE 映射表,
const nodeMap = Object.fromEntries(
    wenjian1.map(it => [it.cateId, it])
);

// 建树,选建个虚根
const root = { list: [] };
// 再遍历节点生成树
wenjian1.forEach(it => {
    ((nodeMap[it.catePId] ?? root).list ??= []).push(it);
});

// 遍历 wenjian2 把数据加进进去
wenjian2.forEach(it => {
    const category = nodeMap[it.cateId];
    if (!category) { return; }  // 没找到分类还能怎样?
    (category.list ??= []).push(it);
});

console.dir(root, { depth: null });

上面的方法直接使用了原节点数据,按题主的结果示例,是需要去掉某些非关键信息的,或者说重新生成的对象,那么就需要改一笖

const nodeMap = Object.fromEntries(
    // 直接使用需要的属性建立目标对象
    wenjian1.map(({ cateId, cageName }) => [cateId, { cateId, cageName }])
);

const root = { list: [] };
wenjian1.forEach(({ cateId, catePId }) => {
    // 不能直接使用原节点,要按 cateId 来找到新建的节点对象
    const node = nodeMap[cateId];
    ((nodeMap[catePId] ?? root).list ??= []).push(node);
});

// 通过参数解构来得到新的节点对象(只需要从原对象排除掉 cateId 就行)
wenjian2.forEach(({ cateId, ...tagNode }) => {
    const category = nodeMap[cateId];
    if (!category) { return; }
    (category.list ??= []).push(tagNode);
});

console.dir(root, { depth: null });

参阅:从列表生成树

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题