计算树数据中所有值的总和。

huangapple go评论52阅读模式
英文:

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

以下是翻译好的部分:

  1. 首先找出所有作为父节点的节点。
  2. 对于每个父节点,需要计算其子节点的总值。
  3. 如果一个子节点没有总值,那么它的总值就是其自身子节点的总和。
  4. 如果一个节点既没有总值,也没有任何子节点,那么它不会对其父节点的总值有贡献。
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:

  1. first find out all nodes that are parent nodes.
  2. for each parent node, you need to sum the total values of its child nodes.
  3. if a child node doesn't have a total value, then its total is the sum of its own child nodes.
  4. 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 =&gt; &#39;total&#39; 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 = &#39;total&#39; in parent ? parent.total + item.total : item.total;
}
}
arr.forEach(item =&gt; 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 =&gt; !parentIds.has(item.id))) {
// walk through parents of a leaf node and add to their totals
// if the total isn&#39;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) &amp;&amp; (parent.total = item.total);
}
}
arr.forEach(item =&gt; 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) =&gt; {
    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

huangapple
  • 本文由 发表于 2023年7月10日 12:02:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76650618.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定