关于递归问题 js

原数据格式

let obj =[
        {1:'20190805',2:'1',3:'success'},
        {1:'20191120',2:'1.1',3:'success'},
        {1:'20190212',2:'1.1.1',3:'success'},
        {1:'20190212',2:'1.1.2',3:'success'},
        {1:'20190212',2:'1.1.3',3:'success'},
        {1:'20190212',2:'1.2',3:'success'},
        {1:'20190212',2:'1.2.1',3:'success'},
        {1:'20190212',2:'2',3:'success'},
        {1:'20190212',2:'2.1',3:'success'},
        {1:'20190212',2:'2.2.1',3:'success'},
        {1:'20190212',2:'2.2',3:'success'},
        {1:'20190212',2:'2.3',3:'success'},
        {1:'20190212',2:'2.3.1',3:'success'},
        ...
        ]

最后想要下面这种结果格式,请问该怎么实现呢

let data = [
        {1: '20190805', 2: '1', 3: 'success', children: [
            {1: '20191120', 2: '1.1', 3: 'success', children: [
                {1: '20190212', 2: '1.1.1', 3: 'success'},
                {1: '20190212', 2: '1.1.2', 3: 'success'},
                {1: '20190212', 2: '1.1.3', 3: 'success'},
            ]}, {1: '20191120', 2: '1.2', 3: 'success', children: [
                    {1: '20190212', 2: '1.2.1', 3: 'success'},
                ]
            }]
        },
        {1: '20190212', 2: '2', 3: 'success', children: [
            {1: '20190212', 2: '2.1', 3: 'success', children: [
                {1: '20190212', 2: '2.2.1', 3: 'success'},
            ]},
            {1: '20190212', 2: '2.2', 3: 'success'},
            {1: '20190212', 2: '2.3', 3: 'success', children: [
                {1: '20190212', 2: '2.3.1', 3: 'success'}]
            }]
        },
        ...
    ]
阅读 2.9k
5 个回答
/**
 *
 * @param {Array} source
 * @returns {Array} 分类好的数据
 */
function mark(source) {
  var temp = {};
  source.forEach(item => {
    temp[item["2"]] = item;
  });
  source.forEach(item => {
    var key = item["2"],
      parent;
    //子级
    if (key.length > 1) {
      //子级的父 id
      key = key.slice(0, -2);
      parent = temp[key];
      if (parent) {
        parent.children = parent.children || [];
        parent.children.push(item);
      }
    }
  });
  return Object.keys(temp).reduce((ret, key) => ret.concat(key.length === 1 ? temp[key] : []), []);
}

1楼的代码有点局限性,稍微整改了一下:

/*
    @params permission 需要整合的数据(不一定有序)
    @return []
*/
// 匹配父级的正则
const REG_CODE = /^(.+)\.\d+$/; 
const handlePermission = permission => {
    // 数据备份,防止污染原数据
    permission = permission.map(item => Object.assign({}, item));

    // 对数据进行排序
    permission.sort((a, b) => a[2] - b[2]);

    // 将每一条数据都当做父级
    let parents = permission.reduce((data, item) => (data[item[2]] = item, data), {});

    // 返回结果
    let res = [];

    // 查找每一条数据对应的父级
    permission.forEach(item => {
        //获取父级code
        let parentCode = REG_CODE.exec(item[2]);

        // 不存在父级,则是顶级父类
        if(!parentCode){
           res.push(item);
           return;
        }

        // 如果存在父级,则挂载到父级的children中
        if(parentCode && parents[parentCode[1]]){
            parents[parentCode[1]].children = parents[parentCode[1]].children || [];
            parents[parentCode[1]].children.push(item);
        }
    });

    return res;
}

配合 lodash 下的 set 函数可以比较简单的实现

const set = require('lodash/set');

[
    { 1: '20190805', 2: '1', 3: 'success' },
    { 1: '20191120', 2: '1.1', 3: 'success' },
    { 1: '20190212', 2: '1.1.1', 3: 'success' },
    { 1: '20190212', 2: '1.1.2', 3: 'success' },
    { 1: '20190212', 2: '1.1.3', 3: 'success' },
    { 1: '20190212', 2: '1.2', 3: 'success' },
    { 1: '20190212', 2: '1.2.1', 3: 'success' },
    { 1: '20190212', 2: '2', 3: 'success' },
    { 1: '20190212', 2: '2.1', 3: 'success' },
    { 1: '20190212', 2: '2.2.1', 3: 'success' },
    { 1: '20190212', 2: '2.2', 3: 'success' },
    { 1: '20190212', 2: '2.3', 3: 'success' },
    { 1: '20190212', 2: '2.3.1', 3: 'success' },
].reduce((f, l) => set(f, l['2'].split('.').map(item => item - 1).join('.children.'), l), []);

我的方法比较笨 哈哈

function transData (datas,num) {
    num = num?num:1
    var res = [],sub = [];

    //先筛选当前的根元素
    datas.forEach(function (item) {
        var arr = item['2'].split('.');
        if (arr.length==num){
            res.push(item)
        }else{
            sub.push(item)
        }
    })

    //然后筛选当前的根元素的子元素
    sub.forEach(function (item) {
        var key = item['2'].split('.').slice(0,num).join('.')
        res.forEach(function(itemIn){
            if (itemIn['2'] == key) {
                !itemIn.children&&(itemIn.children=[])
                itemIn.children.push(item)
            }
        })
    })

    //再递归处理子元素的相对关系
    res.forEach(function (item) {
        if (item.children&&item.children.length>0){
            item.children = transData(item.children,num+1)
        }
    })
    
    return res;
}

var result = transData(obj);
console.log(result)

(事实上使用String.prototype.slice以及.length === 1方法判断是否是为父级不准确,但是只是为了写出思路)

function fn(data, parentPath = null) {
  return data.filter(item => {
    if (parentPath === null && item[2].length === 1 || item[2].slice(0, -2) === parentPath) {
      item.children = fn(data, item[2])
      return true
    }
  })
}

展开(便于阅读):

function fn(data, parentPath = null) {
  return data.filter(item => {
    if (parentPath === null && item[2].length === 1) {
      item.children = fn(data, item[2])
      return true
    }
    if(item[2].slice(0, -2) === parentPath) {
      item.children = fn(data, item[2])
      return true
    }
  })
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题