在(深层)嵌套的对象数组中,我有一个平面的对象数组。
我的平面数组(ID实际上是随机的,但为了清楚起见在此进行了更改,并且嵌套可能很深):
const tags = [
{
id: 'tag1',
title: 'Tag 1',
childIds: ['tag11', 'tag12'],
root: true
},
{
id: 'tag11',
title: 'Tag 11',
childIds: ['tag111', 'tag112'],
},
{
id: 'tag12',
title: 'Tag 12',
childIds: ['tag121']
},
{
id: 'tag111',
title: 'Tag 111',
childIds: []
},
{
id: 'tag112',
title: 'Tag 112',
childIds: []
},
{
id: 'tag121',
title: 'Tag 121',
childIds: []
}
]
我想要的输出:
tagsNested = [
{
id: 'tag1',
title: 'Tag 1',
tags: [
{
id: 'tag11',
title: 'tag 11',
tags: [
{
id: 'tag111',
title: 'Tag 111',
tags: []
},
{
id: 'tag112',
title: 'Tag 112',
tags: []
}
]
},
{
id: 'tag12',
title: 'tag 12',
tags: [
{
id: 'tag121',
title: 'Tag 121',
tags: []
}
]
}
]
}
]
到目前为止,我一直努力将所有标签嵌套在任何标签下。
即我确实得到了一个嵌套数组,但是每个标签数组都包含所有标签。
function unflatten(tag, nestedTags) {
if (tag.childIds) {
tag.childIds.forEach((childId) => {
var childTag = tags.find((t) => t.id === childId)
childTag.tags = unflatten(childTag, nestedTags)
nestedTags.push(childTag)
})
}
return nestedTags
}
const rootTag = tags.find((tag) => tag.root)
console.log(unflatten(rootTag, []))
我真的很难使用这些递归函数,并且弄清楚如何使return语句为我提供正确的数据。
答案 0 :(得分:2)
您可以使用Map来为每个节点设置关键点,然后从中创建新的对象格式。最后,从地图中删除具有父项的条目,以便保留根。因此,实际上不需要root
属性。它从给定的关系间接得出。此算法不使用该属性:
const tags = [{id: 'tag1',title: 'Tag 1',childIds: ['tag11', 'tag12'],root: true},{id: 'tag11',title: 'Tag 11',childIds: ['tag111', 'tag112'],},{id: 'tag12',title: 'Tag 12',childIds: ['tag121']},{id: 'tag111',title: 'Tag 111',childIds: []},{id: 'tag112',title: 'Tag 112',childIds: []},{id: 'tag121',title: 'Tag 121',childIds: []}];
let map = new Map(tags.map(({id, title, childIds}) => [id, { id, title, tags: [] }]));
tags.forEach(tag => map.get(tag.id).tags = tag.childIds.map(id => map.get(id)));
tags.forEach(tag => tag.childIds.forEach(id => map.delete(id)));
let tagsNested = [...map.values()];
console.log(tagsNested);
答案 1 :(得分:2)
这是一种递归方法。它是这样的:
root
标签(或任何标签)和tagsArray
(标签的扁平数组)root
的所有子标签您可以尝试以下代码片段:
const tags = [
{
id: 'tag1',
title: 'Tag 1',
childIds: ['tag11', 'tag12'],
root: true
},
{
id: 'tag11',
title: 'Tag 11',
childIds: ['tag111', 'tag112'],
},
{
id: 'tag12',
title: 'Tag 12',
childIds: ['tag121']
},
{
id: 'tag111',
title: 'Tag 111',
childIds: []
},
{
id: 'tag112',
title: 'Tag 112',
childIds: []
},
{
id: 'tag121',
title: 'Tag 121',
childIds: []
}
]
function buildTag({id, title, childIds}, tagsArray) {
const tags = tagsArray
.filter(tag => childIds.includes(tag.id))
.map(tag => buildTag(tag, tagsArray))
return {
id,
title,
tags,
}
}
const rootTag = tags.find((tag) => tag.root)
console.log([buildTag(rootTag, tags)])
/*
tagsNested = [
{
id: 'tag1',
title: 'Tag 1',
tags: [
{
id: 'tag11',
title: 'tag 11',
tags: [
{
id: 'tag111',
title: 'Tag 111',
tags: []
},
{
id: 'tag112',
title: 'Tag 112',
tags: []
}
]
},
{
id: 'tag12',
title: 'tag 12',
tags: [
{
id: 'tag121',
title: 'Tag 121',
tags: []
}
]
}
]
}
]
*/
答案 2 :(得分:1)
您可以采用迭代方法,将对象作为对节点的引用。
const tags = [{ id: 'tag1', title: 'Tag 1', childIds: ['tag11', 'tag12'], root: true }, { id: 'tag11', title: 'Tag 11', childIds: ['tag111', 'tag112'] }, { id: 'tag12', title: 'Tag 12', childIds: ['tag121'] }, { id: 'tag111', title: 'Tag 111', childIds: [] }, { id: 'tag112', title: 'Tag 112', childIds: [] }, { id: 'tag121', title: 'Tag 121', childIds: [] }],
tree = function (array) {
var t = {},
tree = [];
array.forEach(({ id, title, childIds, root }) => {
Object.assign(
t[id] = t[id] || {},
{ id, title, tags: childIds.map(id => t[id] = t[id] || { id }) }
);
if (root) tree.push(t[id]);
});
return tree;
}(tags);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 3 :(得分:0)
这是一个代码框-https://codesandbox.io/s/green-dawn-3gpvz?file=/src/index.js。与您的要求唯一的区别是结果只是对象而不是数组,但您可以将单个元素包装为数组
function resolveChildren(tag, allTags) {
const { childIds, root, ...rest } = tag;
if (!childIds) return rest;
return {
...rest,
tags: childIds.map(childId =>
resolveChildren(allTags.find(t => t.id === childId), allTags)
)
};
}
resolveChildren(tags.find(tag => !!tag.root), tags)