从对象数组中创建嵌套的数组数据

7
我是一位有用的助手,可以为您提供文本翻译。以下是需要翻译的内容:

我拥有一个对象数组,其中包含嵌套数据的信息,我想将数据转换为实际的嵌套数组数据。如何进行转换:

const data = [
  {id: 1, parent_id: null, name: 'test1'},
  {id: 2, parent_id: null, name: 'test2'},
  {id: 3, parent_id: 2, name: 'test3'},
  {id: 4, parent_id: 2, name: 'test4'},
  {id: 5, parent_id: 4, name: 'test5'},
  {id: 6, parent_id: 4, name: 'test5'},
  {id: 7, parent_id: 2, name: 'test5'},
  {id: 8, parent_id: 2, name: 'test5'},
  {id: 9, parent_id: null, name: 'test5'},
  {id: 10, parent_id: null, name: 'test5'},
]

转换为:

const data = [
  {id: 1, parent_id: null, name: 'test1'},
  {
    id: 2, 
    parent_id: null, 
    name: 'test2',
    children: [
      {id: 3, parent_id: 2, name: 'test3'},
      {
        id: 4, 
        parent_id: 2, 
        name: 'test4',
        children: [
          {id: 5, parent_id: 4, name: 'test5'},
          {id: 6, parent_id: 4, name: 'test5'}
        ]
      },
      {id: 7, parent_id: 2, name: 'test5'},
      {id: 8, parent_id: 2, name: 'test5'},
    ]
  },
  {id: 9, parent_id: null, name: 'test5'},
  {id: 10, parent_id: null, name: 'test5'},
]

什么是最好的做法?
5个回答

6
你可以使用 reduce 方法创建递归函数来实现这个功能。

const data = [{id: 1, parent_id: null, name: 'test1'},{id: 2, parent_id: null, name: 'test2'},{id: 3, parent_id: 2, name: 'test3'},{id: 4, parent_id: 2, name: 'test4'},{id: 5, parent_id: 4, name: 'test5'},{id: 6, parent_id: 4, name: 'test5'},{id: 7, parent_id: 2, name: 'test5'},{id: 8, parent_id: 2, name: 'test5'},{id: 9, parent_id: null, name: 'test5'},{id: 10, parent_id: null, name: 'test5'},]

function nest(data, parentId = null) {
  return data.reduce((r, e) => {
    let obj = Object.assign({}, e)
    if (parentId == e.parent_id) {
      let children = nest(data, e.id)
      if (children.length) obj.children = children
      r.push(obj)
    }
    return r;
  }, [])
}

console.log(nest(data))


3
你可以通过使用对象和idparent_id作为键来采用单循环方法,并将项目/子项收集到其中。
顺序仅对子级数组中的顺序重要。

const
    data = [{ id: 1, parent_id: null, name: 'test1' }, { id: 2, parent_id: null, name: 'test2' }, { id: 3, parent_id: 2, name: 'test3' }, { id: 4, parent_id: 2, name: 'test4' }, { id: 5, parent_id: 4, name: 'test5' }, { id: 6, parent_id: 4, name: 'test5' }, { id: 7, parent_id: 2, name: 'test5' }, { id: 8, parent_id: 2, name: 'test5' }, { id: 9, parent_id: null, name: 'test5' }, { id: 10, parent_id: null, name: 'test5' }],
    tree = function (data, root) {
        var t = {};
        data.forEach(o => {
            Object.assign(t[o.id] = t[o.id] || {}, o);
            t[o.parent_id] = t[o.parent_id] || {};
            t[o.parent_id].children = t[o.parent_id].children || [];
            t[o.parent_id].children.push(t[o.id]);
        });
        return t[root].children;
    }(data, null);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }


这取决于顺序吗?例如,如果 id:1 的父级是 4,它似乎会出现在错误的位置。 - Mark
@MarkMeyer,对于父子关系,顺序并不重要。 - Nina Scholz
嗯,不太确定是什么意思。如果我将id:1的父级从null更改为4,它会出现在错误的位置。 - Mark
请注意,children数组先出现了,但是该项在正确的位置上。 - Nina Scholz
非常抱歉 - 你是对的!只是没能读懂自己的输出 :(。 - Mark

1
这是一个有趣的问题。如果你想保持线性时间,但愿意牺牲一些空间,一种选择是基于 id 创建一个查找对象。然后,您可以循环遍历这些值,并将其推入父对象或数组中:

const data = [{id: 1, parent_id: null, name: 'test1'},{id: 2, parent_id: null, name: 'test2'},{id: 3, parent_id: 2, name: 'test3'},{id: 4, parent_id: 2, name: 'test4'},{id: 5, parent_id: 4, name: 'test5'},{id: 6, parent_id: 4, name: 'test5'},{id: 7, parent_id: 2, name: 'test5'},{id: 8, parent_id: 2, name: 'test5'},{id: 9, parent_id: null, name: 'test5'},{id: 10, parent_id: null, name: 'test5'},]

let lookup = data.reduce((obj, item) => {
  obj[item.id] = item
  return obj
}, {})

let arr = Object.values(lookup).reduce((arr, val) =>{
  if (val.parent_id == null) arr.push(val)
  else (lookup[val.parent_id].children || ( lookup[val.parent_id].children = [])).push(val)
  
  return arr
}, [])

console.log(JSON.stringify(arr, null, 2))


0

你可以尝试这种递归的方法

const data = [{id: 1, parent_id: null, name: 'test1'}, {id: 2, parent_id: null, name: 'test2'}, {id: 3, parent_id: 2, name: 'test3'}, {id: 4, parent_id: 2, name: 'test4'}, {id: 5, parent_id: 4, name: 'test5'}, {id: 6, parent_id: 4, name: 'test5'}, {id: 7, parent_id: 2, name: 'test5'}, {id: 8, parent_id: 2, name: 'test5'}, {id: 9, parent_id: null, name: 'test5'}, {id: 10, parent_id: null, name: 'test5'}];

const transform = arr => {
  return arr.reduce((acc, elem) => {
     const children = data.filter(el => el.parent_id === elem.id),
           isPresent = findDeep(acc, elem);
     if(!isPresent && children.length)
       acc.push({...elem, children: transform(children)});
     else if(!isPresent)
       acc.push(elem);
     return acc;
  }, []);
}


const findDeep =(arr = [], elem) => (
   arr.some(el => (el.id === elem.id) || findDeep(el.children, elem))
);

console.log(transform(data));


-1

const data = [
  {id: 1, parent_id: null, name: 'test1'},
  {id: 2, parent_id: null, name: 'test2'},
  {id: 3, parent_id: 2, name: 'test3'},
  {id: 4, parent_id: 2, name: 'test4'},
  {id: 5, parent_id: 4, name: 'test5'},
  {id: 6, parent_id: 4, name: 'test5'},
  {id: 7, parent_id: 2, name: 'test5'},
  {id: 8, parent_id: 2, name: 'test5'},
  {id: 9, parent_id: null, name: 'test5'},
  {id: 10, parent_id: null, name: 'test5'},
]

const output = data.filter(
  item => !item.parent_id
).map(
  rootItem => ({
    ...rootItem,
    children: data.filter(item => item.parent_id === rootItem.id),
  })
)

console.log(output)


1
id为5的情况是什么? - Mark
啊,你说得对,确实有多个嵌套层级,最好的答案可能是使用reduce函数。 - alexjackson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接