0

I want to calculate the total sum of all the 'val' in this object. The final output should be 113. I tried searching but couldn't find a similar problem on stackoverflow.

const object = {
  val: 10,
  child: [
    {
      val: 20,
      child: [
        {
          val: 25,
          child: []
        },
        {
          val: 28,
          child: []
        }
      ]
    },
    {
      val: 30,
      child: []
    }
  ]
};

What I tried is this. I know this is not the best approach and would love to see a better approach to this.

const object = {
  val: 10,
  child: [
    {
      val: 20,
      child: [
        {
          val: 25,
          child: []
        },
        {
          val: 28,
          child: []
        }
      ]
    },
    {
      val: 30,
      child: []
    }
  ]
};

function sum() {
 let k = object.val;
 if(object.child.length>0){
 object.child.map(item => {
 
 k += item.val;
 if(item.child.length>0){
 item.child.map(item => k += item.val)
 }
 })
 }
 
 return k
}

const result = sum(object);
console.log(result);

You can find the problem here - https://codesandbox.io/s/young-night-ulnfl?file=/src/index.js

I was also thinking something like flat() could have helped but that is only for arrays.

  • Does this answer your question? [Find all values by specific key in a deep nested object](https://stackoverflow.com/questions/54857222/find-all-values-by-specific-key-in-a-deep-nested-object) (instead of pushing to an array, just sum instead) – pilchard Jul 21 '21 at 12:57
  • Also see: [Summing nested value if it exists](https://stackoverflow.com/questions/55750606/summing-nested-value-if-it-exists) – pilchard Jul 21 '21 at 13:27

4 Answers4

1

Recursive Array#reduce()

const object = { val: 10, child: [{ val: 20, child: [{ val: 25, child: [] }, { val: 28, child: [] }] }, { val: 30, child: [] }] };

const sumObjectVals = (arr) => arr
  .reduce((a, obj) => (
    a += (obj.child.length
      ? obj.val + sumObjectVals(obj.child)
      : obj.val), a), 0);

console.log(sumObjectVals([object]))
pilchard
  • 12,414
  • 5
  • 11
  • 23
0
const object = {
  val: 10,
  child: [
    {
      val: 20,
      child: [
        {
          val: 25,
          child: []
        },
        {
          val: 28,
          child: []
        }
      ]
    },
    {
      val: 30,
      child: []
    }
  ]
};

function sum(obj, summ) {
  summ += obj.val;

  if(obj.child.length > 0) {
    obj.child.forEach(x => summ = sum(x, summ))
  }

  return summ;
}

const result = sum(object, 0);
console.log(result);
0

You could create a recursive node visitor function.

const tree = { val: 10, child: [{ val: 20, child: [{ val: 25, child: [] }, { val: 28, child: [] }] }, { val: 30, child: [] }] }

const visitNodes = (obj, visitor, key) => {
  if (typeof obj === 'object') {
    for (let key in obj) {
      visitNodes(obj[key], visitor, key);
    }
  } else {
    visitor(obj, key);
  }
};

let total = 0;
visitNodes(tree, (val, key) => {
  if (key === 'val') {
    total += val;
  }
});
console.log(`Total: ${total}`);

Alternatively, you could have an accumulator that can add all your values for you.

Edit: Altered the function signature to take a custom "child" prop.

const tree = { val: 10, child: [{ val: 20, child: [{ val: 25, child: [] }, { val: 28, child: [] }] }, { val: 30, child: [] }] }

const accumulateValues = (obj, visitor, childProp = null, acc = 0) => {
  if (typeof obj === 'object') {
    acc += visitor(obj);
    if (Array.isArray(obj[childProp])) {
      acc += obj[childProp].reduce((acc, child) =>
        accumulateValues(child, visitor, childProp, acc), 0);
    }
  }
  return acc;
};

const total = accumulateValues(tree, ({ val }) => val, 'child');
console.log(`Total: ${total}`);
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

// You can use multiple reduce array method to get the result.

const object = {
  val: 10,
  child: [
    {
      val: 20,
      child: [
        {
          val: 25,
          child: []
        },
        {
          val: 28,
          child: []
        }
      ]
    },
    {
      val: 30,
      child: []
    }
  ]
};

const results = object.child.reduce((totals, current)=> {
  const innerResult = current.child.reduce((total, cur) => {
    return total + cur.val
  }, 0);
  return totals + current.val + innerResult;
}, object.val);

console.log(results);
Mamunur Rashid
  • 1,095
  • 17
  • 28