如何递归遍历具有 child 数组和 return 最终转换的 objects 数组的对象数组

How to recursively go through an array of ojects with child arrays and return a final transformed array of objects

我希望遍历一个 object,它也可以有 object 的数组,也可以有 object 的数组,等等。理论上这个结构可以是无限的,但它不太可能超过 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',
            }
          ],
        }
      ],
    }
  ],
}

我需要什么样的最终数据结构(首先需要一个默认值object):

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
             ]
          }
        ]
      }
    ]
  }
]

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

这是我得到的最接近的 non-working 解决方案:

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 是否不是这里的最佳解决方案,或者我只是从我的方法中遗漏了一些关键思想。任何帮助将不胜感激。谢谢。

这个怎么样:

// 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) )

因此,如果我没看错的话,您只需要遍历所有对象并将每个对象的 '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: []
            }
          ],
        }
      ],
    }
  ],
}));