
在前端开发或数据处理中,我们经常会遇到需要将扁平化的数据结构转换为具有层级关系的树形结构。例如,一个菜单列表、文件系统路径或组织架构,其原始数据可能是一个简单的数组,每个元素通过一个“层级”或“深度”属性来指示其在整个结构中的位置。
我们的目标是将以下这种扁平化的JSON数组:
const content = [
{ "title": "Item 1", "metaData": { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }},
{ "title": "Item 2", "metaData": { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }},
{ "title": "Item 3", "metaData": { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }},
{ "title": "Item 4", "metaData": { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }},
{ "title": "Item 5", "metaData": { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }}
];转换为如下所示的嵌套结构,其中子项通过subNav属性连接:
[
{
"title": "Item 1",
"metaData": {
"level": 1,
"desc": "Some Desc 1",
"displayOnOverview": true
},
"subNav": [
{
"title": "Item 2",
"metaData": {
"level": 2,
"desc": "Some Desc 2",
"displayOnOverview": true
}
},
{
"title": "Item 3",
"metaData": {
"level": 2,
"desc": "Some Desc 3",
"displayOnOverview": false
},
"subNav": [
{
"title": "Item 4",
"metaData": {
"level": 3,
"desc": "Some Desc 4",
"displayOnOverview": true
}
}
]
}
]
},
{
"title": "Item 5",
"metaData": {
"level": 1,
"desc": "Some Desc 5",
"displayOnOverview": true
}
}
]可以看到,metaData.level属性是构建层级关系的关键。level: 1的项是顶级节点,level: 2的项是level: 1项的子节点,以此类推。
在尝试构建嵌套结构时,一个常见的误区是仅依赖数组的索引和前一个元素的层级来判断父子关系。例如,以下代码片段:
立即学习“Java免费学习笔记(深入)”;
// 初始尝试的代码片段
const root = [];
sideNavData.forEach((node, index) => {
const nodeLevel = node.metaData.level;
if (root.length === 0) {
return root.push(node)
}
const previousLevel = root[index - 1].metaData.level; // 这里的root[index - 1]不一定是正确的父节点
if (previousLevel === nodeLevel) {
return root.push(node)
} else {
return root[index - 1]['subNav'] = node // 错误:这里会直接覆盖,并且可能不是正确的父节点
}
});这种方法的问题在于,root[index - 1]并不总是当前节点在逻辑上的直接父节点。它仅仅是数组中前一个被处理的节点。当层级发生跳变(例如从level 1到level 3,中间没有level 2),或者同一层级有多个兄弟节点时,这种简单的索引依赖就会失效,导致结构错误或覆盖问题。我们需要一种更健壮的机制来追踪每个层级的最新父节点。
为了正确地构建嵌套结构,我们可以采用一种策略,即在遍历扁平数组时,维护一个映射表(itemMap),用于存储每个层级最近处理过的节点。这样,当处理一个新节点时,我们可以根据其level属性轻松找到其对应的父节点(level - 1)。
以下是实现上述逻辑的JavaScript代码:
const content = [
{ title: "Item 1", metaData: { "level": 1, "desc": "Some Desc 1", "displayOnOverview": true }},
{ title: "Item 2", metaData: { "level": 2, "desc": "Some Desc 2", "displayOnOverview": true }},
{ title: "Item 3", metaData: { "level": 2, "desc": "Some Desc 3", "displayOnOverview": false }},
{ title: "Item 4", metaData: { "level": 3, "desc": "Some Desc 4", "displayOnOverview": true }},
{ title: "Item 5", metaData: { "level": 1, "desc": "Some Desc 5", "displayOnOverview": true }}
];
/**
* 将扁平JSON数组转换为嵌套结构
* @param {Array<Object>} data 包含level信息的扁平JSON数组
* @returns {Array<Object>} 转换后的嵌套JSON数组
*/
function buildNestedStructure(data) {
const topLevelItems = []; // 存储所有level 1的顶级节点
const itemMap = {}; // 存储每个level最近处理过的节点,用于查找父节点
for (const item of data) {
// 提取title和metaData,可以根据需要提取更多属性
const { title, metaData } = item;
// 创建一个新的节点对象,避免直接修改原始数据
const newItem = { title, metaData: { ...metaData } }; // 复制metaData以防直接引用问题
if (metaData.level === 1) {
// 如果是顶级节点,直接添加到topLevelItems数组
topLevelItems.push(newItem);
} else {
// 如果是子节点,找到其父节点的层级
const parentLevel = metaData.level - 1;
// 从itemMap中获取父节点
const parentItem = itemMap[parentLevel];
// 检查父节点是否存在,并确保其有subNav数组
if (parentItem) {
if (!parentItem.subNav) {
parentItem.subNav = [];
}
// 将当前节点添加到父节点的subNav中
parentItem.subNav.push(newItem);
} else {
// 实际应用中,如果出现level > 1但找不到父节点的情况,可能需要报错或特殊处理
console.warn(`Warning: Item "${title}" (level ${metaData.level}) has no parent at level ${parentLevel}. It will be orphaned.`);
}
}
// 更新itemMap,将当前newItem存储为当前level的最新节点
// 这样,后续更深层级的节点可以找到它作为父节点
itemMap[metaData.level] = newItem;
}
return topLevelItems;
}
const output = buildNestedStructure(content);
console.log(JSON.stringify(output, null, 2));通过利用一个层级映射表,我们可以有效地将扁平化的JSON数组转换为具有复杂嵌套关系的树形结构。这种方法不仅解决了简单的索引依赖问题,还提供了一种清晰、可扩展且高效的解决方案,适用于各种需要构建层次化数据结构的场景。理解itemMap在追踪父节点中的作用是掌握此技术方案的关键。
以上就是将扁平JSON数组转换为嵌套结构:基于层级信息的JavaScript实现的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号