简体   繁体   English

用对象和数组展平深度嵌套的数组

[英]Flatten a deeply nested array with objects and arrays

I have an array of objects that contain another array with objects.我有一个对象数组,其中包含另一个带有对象的数组。 The nesting is four levels deep.嵌套有四层深。 The structure of the array is:数组的结构是:

[
  {
    title: 'Title',
    type: 'section',
    links: [
      {
        label: 'Label',
        id: 'id_1',
        links: [
          {
            title: 'Title',
            type: 'section',
            links: [
              {
                label: 'Label',
                id: 'id_2',
                links: [
                  {
                    label: 'Label',
                    id: 'id_3',
                    links: [],
                  }
                ]
              }
            ]
          },
          {
            title: 'Other title',
            type: 'section',
            links: [
              {
                label: 'Label',
                id: 'id_4',
                links: [],
              }
            ]
          }
        ]
      }
    ]
  }
]

I want to have a flattened array with the id's of the link arrays that contain links (they are parents of submenu's).我想要一个带有包含链接的链接数组的 id 的扁平数组(它们是子菜单的父级)。 So the desired outcome is like: ["id_1", "id_2"]所以期望的结果是: ["id_1", "id_2"]

I have tried to get the outcome with this function taken from MDN :我试图通过从MDN获取的这个函数来获得结果:

flatDeep(arr, d = 1) {
  return d > 0
    ? arr.reduce((acc, val) =>
      acc.concat(Array.isArray(val.links)
        ? this.flatDeep(val.links, d - 1)
        : val.links), [])
    : arr.slice();
}

This gives me an empty array.这给了我一个空数组。

I think recursive function will simplify.我认为递归函数会简化。 (recursively look for lists array and push the id into res). (递归查找lists数组并将id推入 res)。

 const data = [ { title: "Title", type: "section", links: [ { label: "Label", id: "id_1", links: [ { title: "Title", type: "section", links: [ { label: "Label", id: "id_2", links: [ { label: "Label", id: "id_3", links: [] } ] } ] }, { title: "Other title", type: "section", links: [ { label: "Label", id: "id_4", links: [] } ] } ] } ] } ]; const res = []; const ids = data => { data.forEach(item => { if ("id" in item) { res.push(item.id); } if (item.links) { ids(item.links); } }); }; ids(data); console.log(res);

You could get a flat array with a recursion and a check for id for missing property.您可以获得一个带有递归的平面数组,并检查缺少属性的id

 const getId = ({ id, links }) => [ ...(id === undefined ? [] : [id]), ...links.flatMap(getId) ], data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }], result = data.flatMap(getId); console.log(result);

 var array = JSON.parse('[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_1","links":[{"title":"Title","type":"section","links":[{"label":"Label","id":"id_2","links":[{"label":"Label","id":"id_3","links":[]}]}]},{"title":"Other title","type":"section","links":[{"label":"Label","id":"id_4","links":[]}]}]}]}]'); arr = []; while(array.length != 0) { var ob1 = array.splice(0,1)[0]; for(var ob2 of ob1.links) { if (ob2.links.length !== 0) { arr.push(ob2.id); array = array.concat(ob2.links); } } } console.log(arr);

Here's the output as you requested:这是您要求的输出:

[
  "id_1",
  "id_2"
]

Use Array.flatMap() .使用Array.flatMap() Destructure each object and use an empty array as default for missing id values.解构每个对象并使用空数组作为缺失id值的默认值。 Concat the id and the result of flattening the links recursively.连接id和递归展平链接的结果。

 const flattenIds = arr => arr.flatMap(({ id = [], links }) => [].concat(id, flattenIds(links)) ); const data = [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_1', links: [{ title: 'Title', type: 'section', links: [{ label: 'Label', id: 'id_2', links: [{ label: 'Label', id: 'id_3', links: [] }] }] }, { title: 'Other title', type: 'section', links: [{ label: 'Label', id: 'id_4', links: [] }] }] }] }]; const result = flattenIds(data); console.log(result);

Here is a non-recursive version.这是一个非递归版本。

 const data = [{title:'Title',type:'section',links:[{label:'Label',id:'id_1',links:[{title:'Title',type:'section',links:[{label:'Label',id:'id_2',links:[{label:'Label',id:'id_3',links:[]}]}]},{title:'Other title',type:'section',links:[{label:'Label',id:'id_4',links:[]}]}]}]}]; const stack = data.slice(); const result = []; let obj; while (obj = stack.shift()) { if ("id" in obj && obj.links.length > 0) result.push(obj.id); stack.push(...obj.links); } console.log(result);

This uses breath first, but can easily be changed into depth first.这首先使用呼吸,但可以很容易地先变成深度。 You'll only have to change the stack.push call into stack.unshift .您只需将stack.push调用更改为stack.unshift

For a more detailed explanation about the two, check out Breadth First Vs Depth First .有关两者的更详细说明,请查看广度优先与深度优先

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM