【问题标题】:How to recursively go through an array of ojects with child arrays and return a final transformed array of objects如何递归地遍历具有子数组的对象数组并返回最终转换的对象数组
【发布时间】:2021-09-22 22:05:22
【问题描述】:

我希望循环一个对象,该对象也可以具有对象数组,该对象数组可以具有对象数组,依此类推。从理论上讲,这种结构可能是无限的,但这种方式的深度不太可能超过 12 层。

转换前的数据结构示例:

{
  id: '1234',
  name: 'item 1',
  children: [
    {
      id: '2345',
      name: 'item 2',
      // other properties that I don't care about will be here too
      children: [
        {
          id: '3456',
          name: 'item 3',
          children: [
            {
              id: '4567',
              name: 'item 4',
            }
          ],
        }
      ],
    }
  ],
}

我需要最终的数据结构是什么样的(需要一个默认的第一个对象):

const someArray = [
  {
    // this first child is static and will always be here after transform
    title: 'Projects'
    key: 'projects',
    children: [
      {
        title: 'item 1', // this is 'name' property
        key: '1234,' // this is 'id' property
        children: [
          {
            title: 'item 2',
             key: '2345',
             children: [
               // continue as long as there are children arrays
             ]
          }
        ]
      }
    ]
  }
]

我尝试了几种不同的解决方案,我相信递归函数是解决这个问题的方法,但我只是无法弄清楚如何输出最终结构。我得到了最后两个孩子,但我无法累积以前的孩子。

这是我最接近的非工作解决方案:

const startingObj = [ 
  {
    title: 'Projects',
    key: 'projects',
  }
]

function buildTree (obj) {
  // check if we have a children array with at least 1 child.
  if (obj?.children?.length) {
    return obj?.children.reduce((a, item) => {
      if (a) return {
        ...item.children,
        title: a.name || a.title,
        key: a.id || a.key,
      };
      if (item?.children?.length) return buildTree(item.children);
    }, obj);
  }
}

buildTree(); // would pass in the sample data structure from above here.

我不确定 reduce 是否不是最好的解决方案,或者我只是在我的方法中遗漏了一些关键想法。任何帮助将不胜感激。谢谢。

【问题讨论】:

    标签: recursion transformation reduce


    【解决方案1】:

    这个呢:

    // this function recurses down the tree and for each item it makes a
    // transformed item (saving only the title and key). Then the transformed
    // item is returned and the caller pushes it into the children array
    function buildtree(obj) {
      let item = {
        title: obj.name || obj.title,
        key: obj.id || obj.key,
        children: []
      }
    
      if (obj.children)
        for (child of obj.children)
          item.children.push( buildtree(child) )
    
      return item;
    }
    
    let result = [ 
      {
        title: 'Projects',
        key: 'projects',
        children: []
      }
    ]
    
    result[0].children.push( buildtree(obj) )
    

    这是一个完整的可运行示例:

    obj = {
      id: '1234',
      name: 'item 1',
      x: '', // other properties that I don't care about will be here too
      children: [
        {
          id: '2345',
          name: 'item 2',
          x: '', // other properties that I don't care about will be here too
          children: [
            {
              id: '3456',
              name: 'item 3',
              x: '', // other properties that I don't care about will be here too
              children: [
                {
                  id: '4567',
                  name: 'item 4',
                  x: '', // other properties that I don't care about will be here too
                },
                {
                  id: '5678',
                  name: 'item 5',
                  x: '', // other properties that I don't care about will be here too
                }
              ]
            },
            {
              id: '6789',
              name: 'item 6',
              x: '', // other properties that I don't care about will be here too
              children: [
                {
                  id: '7890',
                  name: 'item 7',
                  x: '', // other properties that I don't care about will be here too
                },
                {
                  id: '890a',
                  name: 'item 8',
                  x: '', // other properties that I don't care about will be here too
                }
              ]
            }
          ]
        },
        {
          id: '90ab',
          name: 'item 9',
          x: '', // other properties that I don't care about will be here too
          children: [
            {
              id: '0abc',
              name: 'item 10',
              x: '', // other properties that I don't care about will be here too
              children: [
                {
                  id: 'abcd',
                  name: 'item 11',
                  x: '', // other properties that I don't care about will be here too
                },
                {
                  id: 'bcde',
                  name: 'item 12',
                  x: '', // other properties that I don't care about will be here too
                }
              ]
            },
            {
              id: 'cdef',
              name: 'item 13',
              x: '', // other properties that I don't care about will be here too
              children: [
                {
                  id: 'defg',
                  name: 'item 14',
                  x: '', // other properties that I don't care about will be here too
                },
                {
                  id: 'efgh',
                  name: 'item 15',
                  x: '', // other properties that I don't care about will be here too
                }
              ]
            }
          ]
        }
      ]
    }
    
    console.log( JSON.stringify(obj) )
    
    function buildtree(obj) {
      let item = {
        title: obj.name || obj.title,
        key: obj.id || obj.key,
        children: []
      }
    
      if (obj.children)
        for (child of obj.children)
          item.children.push( buildtree(child) )
    
      return item;
    }
    
    let result = [ 
      {
        title: 'Projects',
        key: 'projects',
        children: []
      }
    ]
    result[0].children.push( buildtree(obj) )
    
    console.log( JSON.stringify(result) )
    

    【讨论】:

    • 这不是递归,但这对我来说效果更好。谢谢。
    • @Phorden 当你说“这不是递归”时,这意味着我误解了你想要做的事情。你尝试做的和我做的有什么不同?
    • 对不起,这不是我的意思。我的意思是我不认为我应该推送到一个数组(而不是返回一个全新的数组),但该解决方案仍然运行良好。谢谢!
    【解决方案2】:

    所以,如果我说得对,您只需要遍历所有对象,并将每个对象的“id”键更改为“key”,将“name”键更改为“title”。这是一个递归解决方案:

    function recursiveArray(arr) {
      return arr.map(e => ({
        key: e.id,
        title: e.name,
        children: e.children.length ? recursiveArray(e.children) : []
      }));
    }
    
    function changeKeysOfNestedObject(obj) {
      return {
        key: obj.id, 
        title: obj.name,
        children: obj.children.length ? recursiveArray(obj.children) : []
      };
    }
    
    //test case
    console.log(changeKeysOfNestedObject({
      id: '1234',
      name: 'item 1',
      children: [
        {
          id: '2345',
          name: 'item 2',
          children: [
            {
              id: '3456',
              name: 'item 3',
              children: [
                {
                  id: '4567',
                  name: 'item 4',
                  children: []
                }
              ],
            }
          ],
        }
      ],
    }));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      • 2018-01-17
      • 2020-07-06
      • 2018-04-23
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多