js下json结构转换,搞了2天整蒙圈了,求帮助?

var list = [
    {title:"xxxx",level:0},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:2},
    {title:"xxxx",level:2},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:2},
    {title:"xxxx",level:0},
];

这种数据结构,转换为下面这种结构的:

[
    {
        title:"xxxx",
        items:[]
    },
    {
        title:"xxxx",
        items:[
            {
                title:"xxxx",
                items:[]
            },
            {
                title:"xxxx",
                items:[]
            },
            {
                title:"xxxx",
                items:[
                    {
                        title:"xxxx",
                        items:[]
                    },
                ]
            },
        ]
    }
    ...
]

level代表层级,1属于上一个0的子集,2属于上一个1的子集。。。可能会有N级
谁能帮忙写出这个转换函数?

阅读 9.8k
12 个回答
const list = [
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:0},
];

function arrayToJson(list){
    const length=list.length
    let result=[]
    for(let i=0;i<length;i++){
        //为0直接压入
        if(list[i].levle==0){
            result.push({title:list[i].title,items:[]})
        }else
        {
            //压入发生在结果数组尾端,取尾端最高级对象
            let obj=result[result.length-1]
            //若level大于1则循环赋值,找到应该被加入的items数组
            if(list[i].levle>1) {
                for (let j = 0; j < list[i].levle - 1; j++) {
                    //应被加入的items数组位于上一级items的末尾
                    obj = obj.items[obj.items.length - 1]
                }
            }
            //此时无论level为1或是大于1,都已经找到了对应的items,push即可
            obj.items.push({title:list[i].title,items:[]})
        }
    }
    return result
}

let a = JSON.stringify(arrayToJson(list));
console.log(a);


有\r\n是因为控制台复制了换行。我刚转js,语法用的es6标准。

代码

var list = [
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:0},
]

var toTree = (list, levle = 0) => list.reduce((acc, cur, idx, arr) => (cur.levle == levle && acc.push({title: cur.title, levle: cur.levle, items: toTree(list.slice(idx + 1).map((item, _, array) => (item.levle == levle && (array.length = 0), item)), levle + 1)}), acc), []);
toTree(list);

结果

[
  {
    "title": "xxxx",
    "levle": 0,
    "items": []
  },
  {
    "title": "xxxx",
    "levle": 0,
    "items": [
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": [
          {
            "title": "xxxx",
            "levle": 2,
            "items": []
          },
          {
            "title": "xxxx",
            "levle": 2,
            "items": []
          }
        ]
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      }
    ]
  },
  {
    "title": "xxxx",
    "levle": 0,
    "items": [
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      }
    ]
  },
  {
    "title": "xxxx",
    "levle": 0,
    "items": [
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      }
    ]
  },
  {
    "title": "xxxx",
    "levle": 0,
    "items": [
      {
        "title": "xxxx",
        "levle": 1,
        "items": []
      },
      {
        "title": "xxxx",
        "levle": 1,
        "items": [
          {
            "title": "xxxx",
            "levle": 2,
            "items": []
          }
        ]
      }
    ]
  },
  {
    "title": "xxxx",
    "levle": 0,
    "items": []
  }
]
var data = [
    {title:"xxxx",level:0},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:2},
    {title:"xxxx",level:2},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:0},
    {title:"xxxx",level:1},
    {title:"xxxx",level:1},
    {title:"xxxx",level:2},
    {title:"xxxx",level:0},
];

function formatData (data) {
  let levelMap = [],
      result = [];
  
  data.forEach(obj => {
    levelMap[obj.level] = obj;
    
    let parentLevel = obj.level - 1;
    
    if (parentLevel === -1) {
      return result.push(obj);
    }
    
    let parentObj = levelMap[parentLevel];
    
    if (!parentObj) {
      return;
    }
    
    parentObj.items = parentObj.items || [];
    
    parentObj.items.push(obj);
    
  });
  
  return result;
}

console.log(formatData(data))

对最近的层级对象进行入栈即可,简单好理解的算法。
复杂度为 O(n);

const toTree = (list) => {
    list[0].item = [];
    const res = [list[0]];
    const stack = [list[0]];
    for (let i = 1; i < list.length; i++) {
        const item = list[i];
        item.items = [];
        stack[item.levle] = item;
        if( !item.levle ) {
            res.push( item );
            continue;
        }
        stack[item.levle-1].items.push(item);
    }
    return res;
}
function fn(data, lev = 0) {
      let arr = []
      arr = data.filter((item) => {
        return item.levle === lev
      })
      if (arr.length !== 0) {
         // 为了区别添加了levle
        arr = arr.map((item) => {
          return { title: item.title, levle: item.levle, items: [] }
        })
        arr[arr.length - 1].items = fn(data, ++lev)
      }
      return arr
}
fn(list)
var list = [
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:0},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:1},
    {title:"xxxx",levle:2},
    {title:"xxxx",levle:0},
];

let cleanDataFS = (data, dataO) => {
    let datalist = data,
        dataObj  = [];
    if(!datalist[0].id){
        let parentIdFS = (num, dataitem)=>{
            for (let index = num; index > 0; index--) {
                const element = datalist[index];
                if(dataitem.levle > element.levle){
                    return element.id;
                }
            }
        }
        for (let index = 0; index < datalist.length; index++) {
            const element = datalist[index];
            datalist[index].id = 'indexId_' + index;
            if(index){
                datalist[index].parentId = parentIdFS(index, datalist[index])
            }
        }
    }
    let dataObjFS = (dataVal, dataItem)=>{
        for (let index = 0; index < dataVal.length; index++) {
            const element = dataVal[index];
            if(element.id == dataItem.parentId){
                element.items.push({
                    ...dataItem,
                    items: [],
                })
            }else{
                dataObjFS(element.items, dataItem)
            }
        }
    }
    for (let index = 0; index < datalist.length; index++) {
        const element = datalist[index];
        if(!datalist[index].parentId){
            dataObj.push({...element, items:[]});
        }else{
            dataObjFS(dataObj, element);
        }
    }
    return JSON.stringify(dataObj);
}
"[{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_0\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_1\",\"items\":[{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_2\",\"parentId\":\"indexId_1\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_3\",\"parentId\":\"indexId_1\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_4\",\"parentId\":\"indexId_1\",\"items\":[{\"title\":\"xxxx\",\"levle\":2,\"id\":\"indexId_5\",\"parentId\":\"indexId_4\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":2,\"id\":\"indexId_6\",\"parentId\":\"indexId_4\",\"items\":[]}]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_7\",\"parentId\":\"indexId_1\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_8\",\"parentId\":\"indexId_1\",\"items\":[]}]},{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_9\",\"items\":[{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_10\",\"parentId\":\"indexId_9\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_11\",\"parentId\":\"indexId_9\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_12\",\"parentId\":\"indexId_9\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_13\",\"parentId\":\"indexId_9\",\"items\":[]}]},{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_14\",\"items\":[{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_15\",\"parentId\":\"indexId_14\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_16\",\"parentId\":\"indexId_14\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_17\",\"parentId\":\"indexId_14\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_18\",\"parentId\":\"indexId_14\",\"items\":[]}]},{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_19\",\"items\":[{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_20\",\"parentId\":\"indexId_19\",\"items\":[]},{\"title\":\"xxxx\",\"levle\":1,\"id\":\"indexId_21\",\"parentId\":\"indexId_19\",\"items\":[{\"title\":\"xxxx\",\"levle\":2,\"id\":\"indexId_22\",\"parentId\":\"indexId_21\",\"items\":[]}]}]},{\"title\":\"xxxx\",\"levle\":0,\"id\":\"indexId_23\",\"items\":[]}]"

最传统的写法,可以自己优化一下

levle是拼错了吧

function buildTree(list) {
    const root = [];
    const path = [];
    let currentNode = root;
    for (const item of list) {
        if (item.level < path.length) {
            while (item.level !== path.length) {
                currentNode = path.pop();
            }
        } else if (item.level === path.length + 1) {
            path.push(currentNode);
            currentNode = currentNode[currentNode.length - 1].items;
        } else if (item.level !== path.length) {
            throw new Error('数据有问题')
        }
        currentNode.push({
            title: item.title,
            items: []
        });
    }
    return root;
}

这有问题吧,只有层级,没有具体的父节点信息

考虑每次循环时返回当前的祖先链,这样方便最快查找到父节点

function toTree(arr) {
  const res = []
  arr.reduce((pre, curr) => {
    curr.items = []
    if (curr.levle === 0) {
      res.push(curr)
      return [curr]
    }
    for (let i = pre.length - 1; i > -1; i--) {
      if (curr.levle === pre[i].levle + 1) {
        pre[i].items.push(curr)
        pre.length = i + 1
        pre.push(curr)
        break
      }
    }
    return pre
  }, null)
  return res
}
新手上路,请多包涵

不太理解题主的表述,level为0的项有N个,那么最终的数据结构中,有N个level为0的项下的节点是一样的?

1属于上一个0的子集,楼主表述的是什么意思,1属于上一个临近的0的子集吗,还是level为0的节点,都是一样的

推荐问题
宣传栏