James Ives
James Ives

Reputation: 3365

Summing nested value if it exists

I have an array that looks like this:

const values = [
  {
    value: 2000,
    items: [
      {
        value: 300,
      },
    ],
  },
]

I want to sum the total of all of the values in values.value, and if a values.items.value exists I also want to include it in my sum.

values.reduce((total, obj) => obj.value + total, 0);

What would be the correct way to key into the nested array so it sums both the top and nested value key in my reduce function? The output I'd like is 2300 but right now I can only get one level deep, and it's outputting 2000.

Upvotes: 1

Views: 768

Answers (4)

benvc
benvc

Reputation: 15130

You could nest your reduce approach to handle the inner array while ensuring that the key exists in the inner array objects.

const values = [
  {
    value: 2000,
    items: [
      {
        value: 300,
      },
    ],
  },
];

const total = values.reduce((acc, obj) => {
  acc += obj.value;
  acc += obj.items.reduce((a, o) => 'value' in o ? o.value + a : a, 0);
  return acc;
}, 0);

console.log(total);
// 2300

Upvotes: 3

Nina Scholz
Nina Scholz

Reputation: 386600

You could iterate keys/values of the object and sum the a nested object and take the wanted key or zero as start value.

function sum(object, key) {
    return Object.entries(object).reduce((s, [k, v]) => {
        if (v && typeof v === 'object') return s + sum(v, key);
        return s;
    }, key in object ? object[key] : 0);
}

const values = [{ value: 2000, items: [{ value: 300 }] }];

console.log(sum(values, 'value'));

Upvotes: 0

Shidersz
Shidersz

Reputation: 17190

I will add an inner reduce() to get the accumulated sum for the items array. Also, I will add some checks with isNaN() and Array.isArray() just for safety:

const values = [
  {value: 2000, items: [{value: 300}]},
  {value: 3000},
  {value: 2000, items: [{value: 300}, {foo: 20}]},
  {nothing: "nothing"}
];

let res = values.reduce((acc, {value, items}) =>
{
    acc += isNaN(value) ? 0 : value;
    acc += Array.isArray(items) ?
           items.reduce((sum, {value}) => sum + (isNaN(value) ? 0 : value), 0) :
           0;
    return acc;
}, 0);

console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Upvotes: 0

Code Maniac
Code Maniac

Reputation: 37755

You can use reduce add value and check for items if it's there then add the value of items arrays as well

const values = [{value: 2000,items: [{value: 300,},],},]


let op = values.reduce((op,{value,items}) => {
  op+= value
  if(items && items.length) {
    items.forEach(({value})=> op+=value )
  }
  return op
},0)

console.log(op)

Upvotes: 3

Related Questions