英文:
Sum all value in a tree data
问题
这是输入的数组:
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
我需要格式化这个数组。使用递归函数,父节点中的 "total" 值等于所有子节点中 "total" 值的总和。预期输出如下:
[
{ id: 1, total: 5 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1, total: 3 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
英文:
Here is the input arr:
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
I need to format the arrays. Use recursive function, the value of "total" in parent node = sum all the value of "total" in childs node. The expected output will be:
[
{ id: 1 , total: 5},
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1, total: 3 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
答案1
得分: 3
以下是翻译好的部分:
- 首先找出所有作为父节点的节点。
- 对于每个父节点,需要计算其子节点的总值。
- 如果一个子节点没有总值,那么它的总值就是其自身子节点的总和。
- 如果一个节点既没有总值,也没有任何子节点,那么它不会对其父节点的总值有贡献。
function sumTree(arr) {
let map = {};
let root;
// 创建节点映射并找到根节点
for (let obj of arr) {
map[obj.id] = { ...obj, total: obj.total || 0, children: [] };
if (!obj.parent_id) root = map[obj.id];
}
// 构建树
for (let obj of arr) {
if (obj.parent_id) {
map[obj.parent_id].children.push(map[obj.id]);
}
}
// 递归计算总值的函数
function calculateTotal(node) {
for (let child of node.children) {
calculateTotal(child);
node.total += child.total;
}
}
calculateTotal(root);
// 将树转换回数组的函数
function flattenTree(node) {
let res = [];
for (let child of node.children) {
res = res.concat(flattenTree(child));
}
return [{ id: node.id, parent_id: node.parent_id, total: node.total }].concat(res);
}
return flattenTree(root);
}
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
console.log(sumTree(arr));
英文:
ok so for this you need to consider following things:
- first find out all nodes that are parent nodes.
- for each parent node, you need to sum the total values of its child nodes.
- if a child node doesn't have a total value, then its total is the sum of its own child nodes.
- if a node doesn't have a total and also doesn't have any child nodes, then it doesn't contribute to the total of its parent node.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function sumTree(arr) {
let map = {};
let root;
// Create nodes map and find root
for(let obj of arr) {
map[obj.id] = {...obj, total: obj.total || 0, children: []};
if(!obj.parent_id) root = map[obj.id];
}
// Build tree
for(let obj of arr) {
if(obj.parent_id) {
map[obj.parent_id].children.push(map[obj.id]);
}
}
// Function to calculate total recursively
function calculateTotal(node) {
for(let child of node.children) {
calculateTotal(child);
node.total += child.total;
}
}
calculateTotal(root);
// Function to convert the tree back to an array
function flattenTree(node) {
let res = [];
for(let child of node.children) {
res = res.concat(flattenTree(child));
}
return [{id: node.id, parent_id: node.parent_id, total: node.total}].concat(res);
}
return flattenTree(root);
}
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
console.log(sumTree(arr));
<!-- end snippet -->
答案2
得分: 3
如果只有叶节点包含 total
:
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
// 按 ID 将项目收集到数组中,以供进一步遍历树
const map = {};
for (const item of arr) {
map[item.id] = item;
}
// 我们只在叶节点中有总数,因此筛选它们并进行迭代
for (const item of arr.filter(item => 'total' in item)) {
// 遍历叶节点的父节点并将其总数相加
let parent = item;
while (parent = map[parent.parent_id]) {
parent.total = 'total' in parent ? parent.total + item.total : item.total;
}
}
arr.forEach(item => console.log(JSON.stringify(item)));
否则,查找叶节点(这也是在更改某些叶节点时更新父节点的情况):
const arr = [
{ id: 1, total: 100 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1, total: 1000 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
// 按 ID 将项目收集到数组中,以供进一步遍历树
const map = {};
// 找到父级 ID 以筛选叶节点
const parentIds = new Set;
for (const item of arr) {
map[item.id] = item;
parentIds.add(item.parent_id);
}
const touchedParents = new Set;
// 我们只在叶节点中有总数,所以筛选它们并进行迭代
for (const item of arr.filter(item => !parentIds.has(item.id))) {
// 遍历叶节点的父节点并将其总数相加
// 如果总数尚未更新(已触摸),则初始化它
let parent = item;
while (parent = map[parent.parent_id]) {
touchedParents.has(parent) ? parent.total += item.total : touchedParents.add(parent) && (parent.total = item.total);
}
}
arr.forEach(item => console.log(JSON.stringify(item)));
不含代码的部分已经翻译完毕。
英文:
If only leaf nodes contain total
:
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-js -->
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
// collect items into an array by ID for further tree walking
const map = {};
for (const item of arr) {
map[item.id] = item;
}
// we have totals only in leaf nodes so filter them and iterate
for (const item of arr.filter(item => 'total' in item)) {
// walk through parents of a leaf node and add to their totals
let parent = item;
while (parent = map[parent.parent_id]) {
parent.total = 'total' in parent ? parent.total + item.total : item.total;
}
}
arr.forEach(item => console.log(JSON.stringify(item)));
<!-- end snippet -->
Otherwise find leaf nodes (this is also for updating parents when some leaf is changed):
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const arr = [
{ id: 1, total: 100 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1, total: 1000 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
// collect items into an array by ID for further tree walking
const map = {};
// find parent IDs to filter leaf nodes
const parentIds = new Set;
for (const item of arr) {
map[item.id] = item;
parentIds.add(item.parent_id);
}
const touchedParents = new Set;
// we have totals only in leaf nodes so filter them and iterate
for (const item of arr.filter(item => !parentIds.has(item.id))) {
// walk through parents of a leaf node and add to their totals
// if the total isn't updated (touched) yet, init it
let parent = item;
while (parent = map[parent.parent_id]) {
touchedParents.has(parent) ? parent.total += item.total : touchedParents.add(parent) && (parent.total = item.total);
}
}
arr.forEach(item => console.log(JSON.stringify(item)));
<!-- end snippet -->
答案3
得分: 1
在我看来,我们应该将它转换为一棵树,这种思维方式可以帮助我们养成以数据结构的方式思考的良好习惯。
然后,您可以使用深度优先搜索(DFS)来打印出您的想法结果。
英文:
In my opinion, We should transform it to a tree, This mindset can help us develop a good habit of thinking in terms of data structures
const arr = [
{ id: 1 },
{ id: 11, parent_id: 1, total: 2 },
{ id: 12, parent_id: 1 },
{ id: 121, parent_id: 12, total: 1 },
{ id: 122, parent_id: 12, total: 2 }
];
function buildTree(arr) {
const tree = [];
const map = new Map();
for (const item of arr) {
map.set(item.id, { ...item, children: [] });
}
for (const item of arr) {
if (item.parent_id) {
const parent = map.get(item.parent_id);
if (parent) {
parent.children.push(map.get(item.id));
}
} else {
tree.push(map.get(item.id));
}
}
const calculateTotal = (node) => {
let total = node.total || 0;
for (const child of node.children) {
total += calculateTotal(child);
}
node.total = total;
return total;
};
for (const node of tree) {
calculateTotal(node);
}
return tree;
}
const tree = buildTree(arr);
Then you can use DFS to print out your idea result
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论