[英]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.