问一个数据结构转换的问题?

现有一个数组

[
    {id: 1, pk: null, name: '学校'},
    {id: 2, pk: 1, name: '一年级'},
    {id: 3, pk: 1, name: '二年级'},
    {id: 4, pk: 1, name: '三年级'},
    {id: 6, pk: 2, name: '一班'},
    {id: 7, pk: 2, name: '二班'},
    {id: 8, pk: 2, name: '三班'},
    {id: 9, pk: 2, name: '四班'},
    {id: 10, pk: 3, name: '一班'},
    {id: 11, pk: 3, name: '二班'},
    {id: 12, pk: 3, name: '三班'},
    {id: 13, pk: 3, name: '四班'},
    {id: 14, pk: 4, name: '一班'},
    {id: 15, pk: 4, name: '二班'},
    {id: 16, pk: 4, name: '三班'},
    {id: 17, pk: 4, name: '四班'}
]

pk为null的放在最外层, 子pk对应父id,则当作对应id的children, id转为对应的key,
id为17这一条, pk为4,则对应为三年级的children.

最终转换结果

[{
    title: '学校',
    key: 1,
    children: [{
        title: '一年级',
        key: 2,
        children: [{
            title: '一班',
            key: 6,
        },{
            title: '二班',
            key: 7,
        },{
            title: '三班',
            key: 8,
        },{
            title: '四班',
            key: 9,
        }]
    },{
        title: '二年级',
        key: 3,
        children: [{
            title: '一班',
            key: 10,
        },{
            title: '二班',
            key: 11,
        },{
            title: '三班',
            key: 12,
        },{
            title: '四班',
            key: 13,
        }]
    },{
        title: '三年级',
        key: 4,
        children: [{
            title: '一班',
            key: 14,
        },{
            title: '二班',
            key: 15,
        },{
            title: '三班',
            key: 16,
        },{
            title: '四班',
            key: 17,
        }]
    }]
}]

真实数据可能没那么整齐, 但是转换规则是这样的, 有什么好的转换写法么?

阅读 2.5k
5 个回答
// 结果            
let result = []
// hash 用于快速查找数据
let tempList = []
arr.forEach(item => {
    // 生成待保存结构数据
    let temp = {
        title: item.name,
        key: item.id
    }
    // 存在hash上
    tempList[item.id] = temp
    if (item.pk === null) {
        // 放置最外层
        result.push(temp)
    } else if (tempList[item.pk] !== undefined) {
        // 存在则添加至children中
        if (tempList[item.pk].children === undefined) {
            tempList[item.pk].children = []
        }
        tempList[item.pk].children.push(temp)
    } else {
        // 否则提示错误
        console.log(item + '未找到对应父级')
    }
})
var items = [
  {id: 1, pk: null, name: '学校'},
  {id: 2, pk: 1, name: '一年级'},
  {id: 3, pk: 1, name: '二年级'},
  {id: 4, pk: 1, name: '三年级'},
  {id: 6, pk: 2, name: '一班'},
  {id: 7, pk: 2, name: '二班'},
  {id: 8, pk: 2, name: '三班'},
  {id: 9, pk: 2, name: '四班'},
  {id: 10, pk: 3, name: '一班'},
  {id: 11, pk: 3, name: '二班'},
  {id: 12, pk: 3, name: '三班'},
  {id: 13, pk: 3, name: '四班'},
  {id: 14, pk: 4, name: '一班'},
  {id: 15,pk: 4, name: '二班'},
  {id: 16, pk: 4, name: '三班'},
  {id: 17, pk: 4, name: '四班'}
]
var ret = []
var mids = {}
items.forEach(item => {
  var data = {
    title: item.name,
    key: item.id
  }
  if (!mids[item.pk]) {
    mids[item.id] = data
    ret.push(data)
  } else {
    mids[item.id] = data
    if (!mids[item.pk].children) {
      mids[item.pk].children = []
    }
    mids[item.pk].children.push(data)
  }
})
console.log(ret)
 let result = [];

  const setData = (list, d) => {
    for(let i = 0; i < list.length; i++) {
      if(list[i].key === d.pk) {
        if(!list[i].children) {
          list[i].children = [{key: d.id, title: d.name}];
        } else {
          list[i].children.push({key: d.id, title: d.name});
        }
        return list;
      } else if(list[i].children) {
        setData(list[i].children, d);
      } else {
        return list;
      }
    }
  };

  const data = [
    {id: 1, pk: null, name: '学校'},
    {id: 2, pk: 1, name: '一年级'},
    {id: 3, pk: 1, name: '二年级'},
    {id: 4, pk: 1, name: '三年级'},
    {id: 6, pk: 2, name: '一班'},
    {id: 7, pk: 2, name: '二班'},
    {id: 8, pk: 2, name: '三班'},
    {id: 9, pk: 2, name: '四班'},
    {id: 10, pk: 3, name: '一班'},
    {id: 11, pk: 3, name: '二班'},
    {id: 12, pk: 3, name: '三班'},
    {id: 13, pk: 3, name: '四班'},
    {id: 14, pk: 4, name: '一班'},
    {id: 15,pk: 4, name: '二班'},
  {id: 16, pk: 4, name: '三班'},
  {id: 17, pk: 4, name: '四班'}
  ];

  data.forEach(d => {
    if(!d.pk) {
      result.push({key: d.id, title: d.name});
    } else {
      setData(result, d);
    }
  });

  console.log(result);
let result = [];

let key_map = data.reduce((obj, item) => {
    return ((pk, data) => pk 
        ? (obj[pk] = obj[pk] || []).push(data) 
        : result.push(data))(item.pk, {
            title: item.name,
            key: item.id
    }), obj
}, {});

let key_walker = item => (key => key_map[key] 
    && (item.children = key_map[key]).forEach(key_walker))(item.key)

result.forEach(key_walker)

console.dir(result);

其实思路跟前边几位差不多,替换了一些 if 结构而已。

无限树结构可以用递归

function buildChildren(parents, source) {
    return parents.map(parent => {
        let children = source.find(item => item.pk === parent.id);
        parent.children = buildChildren(children, source);
    });
}

let items = [ ... ];

let result = buildChildren(items.find(item=>!item.pk), items);

随手写的,生产环境可以再优化一下。。

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