
在前端开发或数据处理中,我们经常会遇到需要将线性的、扁平化的数据列表转换成具有层级关系的树状结构。例如,一个网站的导航菜单、文件目录结构或评论回复链等。这些数据通常以数组形式存储,其中每个元素包含一个标识其层级的属性(如 level)。
我们的目标是将以下结构的扁平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": {
"desc": "Some Desc 1",
"displayOnOverview": true
},
"subNav": [
{
"title": "Item 2",
"metaData": {
"desc": "Some Desc 2",
"displayOnOverview": true
}
},
{
"title": "Item 3",
"metaData": {
"desc": "Some Desc 3",
"displayOnOverview": false
},
"subNav": [
{
"title": "Item 4",
"metaData": {
"desc": "Some Desc 4",
"displayOnOverview": true
}
}
]
}
]
},
{
"title": "Item 5",
"metaData": {
"desc": "Some Desc 5",
"displayOnOverview": true
}
}
]核心挑战在于如何根据 level 属性正确地识别父子关系,并将子节点动态地添加到其父节点的 subNav 数组中。
为了高效地构建嵌套结构,我们需要一种机制来追踪当前处理的节点及其潜在的父节点。这里介绍一种基于迭代和映射表的解决方案。
算法思路:
初始化:
迭代处理: 遍历输入的扁平数据数组 data 中的每一个 item。
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
30
节点构建: 对于每个 item,提取其 title 和 metaData。需要注意的是,最终输出的 metaData 不应包含 level 属性,因为 level 仅用于结构构建,而非最终数据负载。因此,我们创建一个新的 newItem 对象,其中 metaData 只包含除 level 之外的其他属性。
判断层级并连接:
更新映射表: 无论当前 item 是顶级节点还是子节点,都需要将其 newItem 存储到 itemMap 中,键为 metaData.level。这样,当前 newItem 就成为了后续更高层级节点的潜在父节点。
返回结果: 遍历结束后,topLevelItems 数组将包含完整的嵌套结构。
以下是使用 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 属性的扁平数据数组。
* @returns {Array<Object>} 转换后的嵌套JSON数组。
*/
function buildNestedStructure(data) {
const topLevelItems = []; // 存储所有 level 1 的顶级节点
const itemMap = {}; // 映射表,键为层级,值为该层级最近处理过的节点
for (const item of data) {
const { title, metaData } = item;
// 解构 metaData,将 level 属性分离,其余属性放入 restMetaData
const { level, ...restMetaData } = metaData;
// 创建新的节点对象,其 metaData 不包含 level 属性
const newItem = { title, metaData: restMetaData };
if (level === 1) {
// 如果是顶级节点,直接添加到 topLevelItems 数组
topLevelItems.push(newItem);
} else {
// 如果是子节点,找到其父节点的层级
const parentLevel = level - 1;
const parentItem = itemMap[parentLevel]; // 从映射表中获取父节点
// 检查父节点是否存在,并确保其有 subNav 数组
if (parentItem) {
if (!parentItem.subNav) {
parentItem.subNav = [];
}
// 将当前新节点添加到父节点的 subNav 数组中
parentItem.subNav.push(newItem);
} else {
// 如果找不到父节点,这可能意味着数据不完整或顺序有误
// 在实际应用中,可以根据需求选择抛出错误或跳过
console.warn(`Warning: Parent item for level ${level} not found for item: ${title}`);
}
}
// 更新 itemMap,将当前新节点作为其层级下的最新节点,供后续子节点查找
itemMap[level] = newItem;
}
return topLevelItems;
}
const output = buildNestedStructure(content);
console.log(JSON.stringify(output, null, 2));通过 itemMap 这种巧妙的数据结构,我们能够高效且清晰地将扁平的层级数据转换为复杂的嵌套树形结构。这种模式在处理各种需要构建层次关系的数据时非常有用,如构建动态导航菜单、组织评论回复、或将文件路径转换为目录树等。理解并掌握这种转换技巧,是处理复杂数据结构的基础能力之一。
以上就是将扁平JSON数据转换为带层级的嵌套结构的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号