最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

recursion - Parent value as sum of all children values within nested javascript object - Stack Overflow

programmeradmin1浏览0评论

I have a deeply nested javascript object with an unlimited amout of children. Every child has a value and a totalValue. The totalValue should be the sum of all the values from all its children and subchildren. How can I make this work?

At the moment I'm only able to loop the whole object using a recursive function:

// Recursive function
_.each(names, function(parent) { 
    if(parent.children.length > 0) { 
        recursiveFunction(parent.children);
    }
});

function recursiveFunction(children){ 
    _.each(children, function(child) { 
        if(child.children.length > 0) { 
            recursiveFunction(child.children)
        }
    });
}; 

// Deeply nested javascript object
var names = {
    name: 'name-1',
    value: 10,
    valueTotal: 0, // should be 60 (name-1.1 + name-1.2 + name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
    children: [{
            name: 'name-1.1',
            value: 10,
            valueTotal: 0,
            children: []
        }, {
            name: 'name-1.2',
            value: 10,
            valueTotal: 0, // should be 40 (name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
            children: [{
                name: 'name-1.2.1',
                value: 10,
                valueTotal: 0,
                children: []
            }, {
                name: 'name-1.2.2',
                value: 10,
                valueTotal: 0, // should be 20 (name-1.2.2.1 + name-1.2.2.2)
                children: [{
                    name: 'name-1.2.2.1',
                    value: 10,
                    valueTotal: 0,
                    children: []
                }, {
                    name: 'name-1.2.2.2',
                    value: 10,
                    valueTotal: 0,
                    children: []
                }]
            }]
        }]
    }
}

I have a deeply nested javascript object with an unlimited amout of children. Every child has a value and a totalValue. The totalValue should be the sum of all the values from all its children and subchildren. How can I make this work?

At the moment I'm only able to loop the whole object using a recursive function:

// Recursive function
_.each(names, function(parent) { 
    if(parent.children.length > 0) { 
        recursiveFunction(parent.children);
    }
});

function recursiveFunction(children){ 
    _.each(children, function(child) { 
        if(child.children.length > 0) { 
            recursiveFunction(child.children)
        }
    });
}; 

// Deeply nested javascript object
var names = {
    name: 'name-1',
    value: 10,
    valueTotal: 0, // should be 60 (name-1.1 + name-1.2 + name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
    children: [{
            name: 'name-1.1',
            value: 10,
            valueTotal: 0,
            children: []
        }, {
            name: 'name-1.2',
            value: 10,
            valueTotal: 0, // should be 40 (name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
            children: [{
                name: 'name-1.2.1',
                value: 10,
                valueTotal: 0,
                children: []
            }, {
                name: 'name-1.2.2',
                value: 10,
                valueTotal: 0, // should be 20 (name-1.2.2.1 + name-1.2.2.2)
                children: [{
                    name: 'name-1.2.2.1',
                    value: 10,
                    valueTotal: 0,
                    children: []
                }, {
                    name: 'name-1.2.2.2',
                    value: 10,
                    valueTotal: 0,
                    children: []
                }]
            }]
        }]
    }
}
Share Improve this question edited Jan 19, 2017 at 16:10 Sam asked Jan 19, 2017 at 15:36 SamSam 1,3433 gold badges24 silver badges41 bronze badges 2
  • 1 your sum looks wrong, name-2 is children of name-1, and should be included. – Nina Scholz Commented Jan 19, 2017 at 16:01
  • 1 Your right! i'll change it. – Sam Commented Jan 19, 2017 at 16:02
Add a ment  | 

4 Answers 4

Reset to default 7

So in fact you wanna do sth like this: every elem asks his childs for its values, these do the same and give back their totalValues plus their own value.

function sumUp(object){
  object.totalValue = 0;
  for(child of object.children){
    object.totalValue += sumUp(child);
   }
   return object.totalValue + object.value;
}

Start like this:

const totalofall = sumUp(names);
console.log(names); //your expected result.

Working example: http://jsbin./laxiveyoki/edit?console

You could use plain Javascript with an iterative and recursive approach and some sanity checks for local totals.

function calculateValues(o) {
    o.valueTotal = (o.children || []).reduce(function (r, a) {
        calculateValues(a);				
        return r + (a.value || 0) + (a.valueTotal || 0);
    }, 0);
}

var names = { name: 'name-1', value: 10, valueTotal: 0, children: [{ name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 0, children: [{ name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 0, children: [{ name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] }] }] }] };

calculateValues(names);
console.log(names);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Not a big fan of reinventing the wheel and would suggest to use a library for readability and maintainability. We use object-scan now for most of our data processing. It is quite versatile once you wrap your head around how to use it. Anyways, here is a possible solution for your question

// const objectScan = require('object-scan');

const injectSums = (data) => {
  objectScan(['**.children'], {
    filterFn: ({ parent, value: children }) => {
      parent.valueTotal = children
        .map(({ valueTotal, value }) => valueTotal + value)
        .reduce((a, b) => a + b, 0);
    }
  })(data);
};

const names = { name: 'name-1', value: 10, valueTotal: 0, children: [ { name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 0, children: [ { name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 0, children: [ { name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] } ] } ] }] };

injectSums(names);

console.log(names);
// => { name: 'name-1', value: 10, valueTotal: 60, children: [ { name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 40, children: [ { name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 20, children: [ { name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] } ] } ] } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>

Disclaimer: I'm the author of object-scan

This works for me. It adds previous count value in object to total count. This can be subtracted later

function sumUpTree(obj, key, totalKey, childrenKey) {
  
  let sumUpTreeInner = (obj) => {
    obj[totalKey] =
      obj[key] +
      (obj[childrenKey] || []).reduce(function (r, child) {
        sumUpTreeInner(child);
        return r + (child[totalKey] || 0);
      }, 0);
  };
  sumUpTreeInner(obj);
}

This is inspired from above answers of Jonas Wilms and Nina Scholz

发布评论

评论列表(0)

  1. 暂无评论