Vladyslav Semeniuk
Vladyslav Semeniuk

Reputation: 557

Reduce arrays in objects that in big array JS

I have a nested array, consisting of a lot of objects (400 items). That objects have an ID property and an incomes property. That incomes property is an array of objects (40 items) that have value and date.Question is, how can I iterate through that main array to sum all my small array values to one summary?

[{id: 1-400, incomes:[{value: "String", date: "String"}]}]

And, for example, that summary will be the 3rd property of main array:

[{id: 1-400, incomes:[{value: "String", date: "String"}], summaryIncome: "number"}]

I can iterate for that 400 items with for in loop, but I don`t understand how can I iterate both for big 400 items and small 40 items arrays with one loop.

 for(let i in data){
   data[i].incomes[i].value
}

So i will be >40 and I`ll get undefined in incomes[i].value. Please help :)

Upvotes: 0

Views: 1027

Answers (2)

Mike
Mike

Reputation: 1327

Sum Array of Objects

Iterate over each object and calculate the sum, assigning it to a new key:

let data = getData()

data.forEach(obj => {
  obj.summaryIncome = obj.incomes.reduce((agg,{value}) => agg+=value, 0);
})

console.log(data);

function getData(){
 return [
  {id: 1, incomes: [{value:1, date:new Date()}, {value: 2, date:new Date()}]}, 
  {id: 2, incomes: [{value:3, date:new Date()}, {value: 4, date:new Date()}]}
 ];
}

This assumes:

  • source data has a value
  • the source data is mutable (can store summaryIncome with it)
  • there is always an incomes and value key
  • it uses reduce to iterate over each value and collect an aggregate, agg, which will hold the item's sum
  • your browser supports ES6 or you have a transpiler for polyfills

Your Issues

400 items is not a lot of items. You should be able to easily iterate them; however, your number of items and the number of values are not a uniform array; it's not a 400x400, it's 400x40. You don't have the same number of ids as you do values for each id. So your i is fine for your item loop, but because you have fewer values than items, you will reach an end.

Even if they were the same number, it doesn't seem there is anything that binds the observation to the number of incomes, so it would be strongly discouraged to only use one loop and/or variable for tracking the index.

For an example of an implementation that uses two loops, refer to the previous section, which uses forEach and reduce to iterate both dimensions of your data. Likewise, below modifies your original code that to demonstrate using two for-loops:

for(let item of data){
   let sum = 0;
   for(let {value} of item.incomes){
     sum += value;
   }
   item.summaryIncome = sum
}

Upvotes: 1

samura
samura

Reputation: 4395

var a = [
  {id: 1, incomes: [{value:1}, {value: 2}]}, 
  {id: 2, incomes: [{value:2}, {value: 3}]}];

var b = a.map(item => ({
  ...item,
  summaryIncome: item.incomes.reduce((t, income) =>
    t += income.value, 0)
}));

console.log(b);

This should print:

{id: 1, incomes: Array(2), summaryIncome: 3}
{id: 2, incomes: Array(2), summaryIncome: 5}

Upvotes: 3

Related Questions