【问题标题】:Flatten a deeply nested array with objects and arrays用对象和数组展平深度嵌套的数组
【发布时间】:2020-07-12 07:43:29
【问题描述】:

我有一个对象数组,其中包含另一个对象数组。嵌套有四层深。 数组的结构是:

[
  {
    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: [],
              }
            ]
          }
        ]
      }
    ]
  }
]

我想要一个扁平数组,其中包含包含链接的链接数组的 id(它们是子菜单的父级)。 所以想要的结果是这样的: ["id_1", "id_2"]

我已尝试使用来自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();
}

这给了我一个空数组。

【问题讨论】:

  • 所以,从给定的对象数组中,您只需要像["id_1", "id_2"]这样的数组?

标签: javascript arrays ecmascript-6


【解决方案1】:

我认为递归函数会简化。 (递归查找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);

【讨论】:

    【解决方案2】:

    您可以获得一个带有递归的平面数组,并检查 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);

    【讨论】:

    • 感谢尼娜!我添加了对空链接数组的检查,其中检查了未定义的 id 以仅返回具有链接的 id。
    【解决方案3】:

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

    这是您要求的输出:

    [
      "id_1",
      "id_2"
    ]
    

    【讨论】:

      【解决方案4】:

      使用Array.flatMap()。解构每个对象,并使用空数组作为默认值来丢失 id 值。连接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);

      【讨论】:

        【解决方案5】:

        这是一个非递归版本。

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

        这首先使用呼吸,但可以很容易地先更改为深度。您只需将stack.push 调用更改为stack.unshift

        有关两者的更详细说明,请查看Breadth First Vs Depth First

        【讨论】:

          猜你喜欢
          • 2016-05-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-13
          • 1970-01-01
          • 1970-01-01
          • 2021-05-14
          • 1970-01-01
          相关资源
          最近更新 更多