0

I have an array of objects:

[{person:101, year: 2012}, {person:102, year: 2012}, {person:103, year: 2013}]

And I want to be able to return an aggregate count for each year (much like a group by in SQL would achieve) in the format of:

[{year: 2012, count:2}, {year: 2013, count:1}]

What is the best way to achieve this in Vanilla Javascript?

2
  • 1
    Would a more useful output format not be {"2012":2, "2013":1}? Because this would be very easy to achieve with a simple loop ;) Commented May 7, 2017 at 11:11
  • 2
    Check that and have a try next time. You have google and not even try? Commented May 7, 2017 at 11:11

4 Answers 4

1

As others have mentioned, an object would be a better fit for aggregating the data. You could use a normal loop, or reduce to do it:

var data = [{person:101, year: 2012}, {person:102, year: 2012}, {person:103,
year: 2013}];

var yearCounts = data.reduce(function (result, person) {
  var currentCount = result[person.year] || 0;
  result[person.year] = currentCount + 1;
  return result;
}, {});

console.log(yearCounts);

If you really need it as an array, you could the loop over the object and convert it to an array:

var data = [{person:101, year: 2012}, {person:102, year: 2012}, {person:103,
year: 2013}];

var yearCounts = data.reduce(function (result, person) {
  var currentCount = result[person.year] || 0;
  result[person.year] = currentCount + 1;
  return result;
}, {});

var year,
  yearCountArray = [];
for (year in yearCounts) {
  if (yearCounts.hasOwnProperty(year)) {
    yearCountArray.push({
      year: year,
      count: yearCounts[year]
    });
  }
}

console.log(yearCountArray);

Sign up to request clarification or add additional context in comments.

Comments

1

You can use a combination of .reduce() with a Map to build a key-value pair object, where the key is the thing you want to group by (ie: year) and the value is the frequency of that property. You can then use Array.from() to build an array of objects from the Map:

const data = [{person:101, year: 2012}, {person:102, year: 2012}, {person:103, year: 2013}];

const res = Array.from(
  data.reduce((map, {year}) => map.set(year, (map.get(year) ?? 0)+1), new Map), 
  ([year, count]) => ({year, count})
);
console.log(res);

Comments

0

You need to use simple for like below :

var data = [{person:101, year: 2011}, 
            {person:102, year: 2012}, 
            {person:103, year: 2011}];


var result = {},
  i;

for(i=0; i < data.length; i++){
  let year = data[i].year;
  if(typeof result[year] === 'undefined'){
    result[year] = 1;
  }
  else{
    result[year] = result[year] + 1;
  }

}

console.log(result);

Comments

0

Use a generic group by key reducer that will count the number of items in each group. I will take inspiration from a previous answer of mine. This function will return another function that act as a reducer, but you can always give it the key that you want as a parameter.

const groupByCounter = key => (result,current) => {
  if (typeof result[current[key]] == 'undefined'){
    result[current[key]] = 1;
  }else{
    result[current[key]]++;
  }
  return result;
};

const data = [{person:101, year: 2012}, {person:102, year: 2012}, {person:103, year: 2013}];

const group = data.reduce(groupByCounter('year'),{});
console.log(group);

2 Comments

Why are you creating an item object?
It was an error, thank you for pointing it out

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.