Stu
Stu

Reputation: 67

Traversing an array of objects and adding to other array based on condition

I have an array containing the following objects.

var notTotal = [{"Year":2012,"Value":800579},
                {"Year":2012,"Value":654090},
                {"Year":2012,"Value":758092},
                {"Year":2013,"Value":343928},...More objects.. ]

What im trying to do is traverse this array of objects where only one Year exists instead of multiple and to add up the Values for that year. Using the example above..

var total = [{"Year":2012,"Value":2556689}, 
//Total of first three 2012 assuming there isnt anymore 2012 in the array 
             {"Year":2013,"Value":343928},...]

I have tried something like the following:

for(var i = 0; i < notTotal.length; i++) {
   if (total.includes(notTotal[i].Year || notTotal[i])) {
      //Add the value of the year in notTotal array to the same year in total array
   } else {
   total.push(notTotal[i]); //add year and value if it does not exist to the total array
 }
}

Apologies if this is a duplicate. It seems like a pretty specific question.

Thanks!

Upvotes: 0

Views: 90

Answers (6)

Seb Morris
Seb Morris

Reputation: 390

An easy solution would be to create an object, holding totals by year.

var totalByYear = {};

You can then loop over the array using notTotal.forEach or a for loop as you've shown, adding to the value of the relevant year inside the totalByYear object.

notTotal.forEach(function(ele) { totalByYear[ele.Year] += ele.Value });

This yields an object with year keys and total values, e.g. using your example:

{'2012': 2556689, '2013': 343928 /* other years */}

The desired format (for D3) can then be built from the totalByYear object (and the totals by year printed):

var totals = [];
for (year in totalByYear) {
    console.log('Total for year ' + year + ' is ' + totalByYear[year]);
    //Build the correctly formatted array
    totals.push({ Year: year, Value: totalByYear[year]});
}

//Prints:
//Total for year 2012 is 2556689
//etc.etc.

The totals array will then have the desired format.

Upvotes: 2

user7791047
user7791047

Reputation:

one more solution :

function yearlyValueFilter(array){
  var yearlyValue = {}  
  array.forEach( (obj) => { //litterate on the input
    var year = obj.Year   
    var value = obj.Value
    if((year in yearlyValue)){  //if the array with not duplicated years conatins the litteration year just plus that value 
      yearlyValue[year] += value
    }else{      //if not conatins, it gets as a basic value
      yearlyValue[year] = value
    }
  })
  return yearlyValue
}

Upvotes: 1

akuiper
akuiper

Reputation: 214927

var notTotal = [{"Year":2012,"Value":800579},
                {"Year":2012,"Value":654090},
                {"Year":2012,"Value":758092},
                {"Year":2013,"Value":343928}]
                
var totalObj = notTotal.reduce((sum, obj) => {
  sum[obj.Year] = sum[obj.Year] + obj.Value || obj.Value;
  return sum;
}, {});

// convert total to the format you need;
var total =  Object.entries(totalObj).map(([Year, Value]) => ({Year, Value}))

console.log(total);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386560

You could use a hash table and check if the year does not exist, then generate a new result set. Then update the total count.

var values = [{ Year: 2012, Value: 800579 }, { Year: 2012, Value: 654090 }, { Year: 2012, Value: 758092 }, { Year: 2013, Value: 343928 }],
    hash = Object.create(null),
    totals = [];
    
values.forEach(function (o) {
    hash[o.Year] || totals.push(hash[o.Year] = { Year: o.Year, Value: 0 });
    hash[o.Year].Value += o.Value;
});

console.log(totals);

Upvotes: 0

Alice Yu
Alice Yu

Reputation: 176

Great question! To explain what's happening in your if (total.includes(notTotal[i].Year || notTotal[i])) is that you are looking through your total array for either just the year, or just an existing notTotal[i] exactly as it is. So your loop is trying to find a value that's exactly 2012 or exactly "Year":2012,"Value":2556689. Ergo, if your total array looked like this:

[{"Year":2012, "Value": 12345}]

your for loop would not find it even though there is an object with 2012 as its year. As for how to fix this, take a look at this previous question!

How to determine if Javascript array contains an object with an attribute that equals a given value?

Hopefully that helps :)

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138257

You could built a hash table:

var hash = {},total=[];
for(const {Year,Value} of notTotal){
  if(hash[Year]){
    hash[Year].Value+=Value;
  }else{
    total.push(hash[Year]={Year,Value});
  }
}

In action

Note: object properties are normally not capitalized...

Upvotes: 0

Related Questions