
在前端开发或数据处理中,我们经常会遇到树形或嵌套的数据结构。假设我们有一个表示分类或层级关系的对象数组,其结构如下:
const data = [
{
key: "id1",
name: "Category 1",
curr: 0,
total: 0,
nodes: [
{
key: "id2",
name: "Applications",
curr: 20,
total: 30,
nodes: [
{
key: "id3",
name: "Gaming",
curr: 5,
total: 10,
nodes: []
},
{
key: "id4",
name: "Operating System",
curr: 15,
total: 20,
nodes: []
}
]
}
]
},
{
key: "id5",
name: "Category 2",
curr: 0,
total: 0,
nodes: [
{
key: "id6",
name: "Sub Category",
curr: 12,
total: 48,
nodes: [
{
key: "id7",
name: "Inside Sub",
curr: 12,
total: 48,
nodes: []
}
]
}
]
},
{
key: "id8",
name: "Last One",
curr: 0,
total: 0,
nodes: []
}
];每个对象都包含一个唯一的 key、name、curr(当前值)、total(总值)以及一个 nodes 数组,用于表示其子节点。我们的目标是实现一个函数,当传入一个 key 时,能够找到对应的节点,将其 curr 值递增,并且将此递增操作向上回溯,使其所有祖先节点的 curr 值也相应递增。但需要特别注意的是,最顶层(根级别,即 data 数组中的直接元素,如 id1, id5, id8)的 curr 值不应被修改。
例如,如果调用 incrementRecursively(data, "id4"),预期输出应为:id4 的 curr 从 15 变为 16,其父节点 id2 的 curr 从 20 变为 21。而 id1(根节点)的 curr 保持不变。
初次尝试解决此类问题时,开发者可能会倾向于使用简单的递归遍历,如下所示:
const incrementRecursively = (nodes, key) => {
const increment = (currentNodes, targetKey) => {
currentNodes.forEach((node) => {
if (node.key === targetKey) {
node.curr++; // 找到目标,递增
}
if (node.nodes && node.nodes.length) {
// 递归处理子节点
increment(node.nodes, targetKey);
}
});
};
increment(nodes, key);
return nodes;
};这种方法的问题在于,它只能找到并修改指定 key 的节点。当目标节点被修改后,它不会向其父节点传递任何信息,因此父节点的 curr 值不会被更新。此外,它也没有机制来区分根节点和其他层级的节点,从而无法实现“不修改根节点”的需求。
为了解决上述问题,我们需要一种机制,让递归函数在子节点发生更新时,能够通知其父节点。同时,我们需要一个参数来追踪当前节点的深度,以便在更新时排除根节点。
function updateParentChildCurr(nodes, targetKey, depth = 0) {
// 遍历当前层级的节点
for (let node of nodes) {
// 检查当前节点是否是目标节点,或者其子节点中是否找到了目标节点并进行了更新
// `node.nodes ?? []` 确保即使 node.nodes 为 undefined 或 null 也能安全地进行递归调用
if (node.key === targetKey || updateParentChildCurr(node.nodes ?? [], targetKey, depth + 1)) {
// 如果满足上述条件(即当前节点或其子节点发生了更新)
// 并且当前节点不是根节点(depth > 0)
if (depth > 0) {
node.curr++; // 递增当前节点的 curr 值
}
// 返回 true,向上层级通知:该路径上发生了更新
return true;
}
}
// 如果遍历完当前层级的所有节点,都没有找到目标或子节点未更新,则返回 false
return false;
}
// 示例调用
console.log("原始数据:", JSON.stringify(data, null, 2));
// 调用函数,更新 key 为 "id4" 的节点及其父节点
updateParentChildCurr(data, 'id4');
console.log("\n更新 'id4' 后的数据:", JSON.stringify(data, null, 2));
// 再次调用,更新 key 为 "id7" 的节点及其父节点
updateParentChildCurr(data, 'id7');
console.log("\n更新 'id7' 后的数据:", JSON.stringify(data, null, 2));代码解析:
通过结合递归遍历、深度追踪参数以及利用函数返回值作为状态传递机制,我们成功地实现了一个高效且准确的解决方案,用于在嵌套对象数组中根据指定键递归更新目标节点及其所有父节点的特定数值,同时遵守了不修改根节点的特定业务规则。这种模式在处理树形数据结构时非常有用,可以灵活应用于各种复杂的层级数据操作场景。
以上就是递归更新嵌套对象中指定键及其祖先节点的数值的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号