Search code examples
javascriptreduce

How to use javascript reduce function to calculate average of items meeting a specific condition?


So assume I have the following array of objects:

var arr = [
  {"name": "John", "score": "8.8"},
  {"name": "John", "score": "8.6"},
  {"name": "John", "score": "9.0"},
  {"name": "John", "score": "8.3"},
  {"name": "Tom",  "score": "7.9"}
];

var count = 0;
var avgScore = arr.reduce(function (sum,person) {
  if (person.name == "John") {
    count+=1;
    return sum + parseFloat(person.score);
  }
  return sum;
},0)/count);

Question: Is there a way way to calculate the average score for "John" without creating a global count variable. Ideally, the count would be internal to the anonymous function in the arr.reduce.


Solution

  • To avoid global variables, use a standard solution like IIFEs or block scopes. However I guess you're looking for a way to avoid a mutable counter.

    The simplest would be to drop all other persons beforehand:

    var johns = arr.filter(function(person) {
      return person.name == "John";
    });
    var avgScore = johns.reduce(function (sum, person) {
      return sum + parseFloat(person.score);
    }, 0) / johns.length;
    

    But you can also use a count that is passed along with the sum in an object:

    var stats = arr.reduce(function ({count, sum}, person) {
      return (person.name == "John")
        ? {count: count+1, sum: sum + parseFloat(person.score)}
        : {count, sum};
    }, {count:0, sum:0})
    var avgScore = stats.sum / stats.count);
    

    (using ES6 object property shorthands and destructuring)