Search code examples
javascriptarraysjavascript-objects

How to calculate the average in JavaScript of the given properties in the array of objects


I have an array of objects. Each object contains a few properties and one of these properties is age.

var people = [
  {
    name: 'Anna',
    age: 22
  },
  {
    name: 'Tom',
    age: 34
  }, {
    name: 'John',
    age: 12
  },
]

I want to calculate the average for all the age properties in this array. I use this function:

let getAverage = arr => {
  let reducer = (total, currentValue) => total + currentValue;
  let sum = arr.reduce(reducer)
  return sum / arr.length;
}

It works fine for the simple array like [22, 34, 12] but it does not for the arrays of objects.

How to modify my getAverage function to make it works also with arrays of object?

Here is the snippet with my code: https://jsfiddle.net/marektchas/kc8Ls0f5/2/


Solution

  • You don't need to modify getAverage - you can pre-process the array before handing it off, in which case getAverage will work exactly as needed:

    var people = [
      {
        name: 'Anna',
        age: 22
      },
      {
        name: 'Tom',
        age: 34
      }, {
        name: 'John',
        age: 12
      },
    ]
    
    let getAverage = arr => {
      let reducer = (total, currentValue) => total + currentValue;
      let sum = arr.reduce(reducer)
      return sum / arr.length;
    }
    
    let ages = people.map(person => person.age);
    
    console.log(getAverage(ages));

    If you want to change getAverage, so it can handle any potential type of input, then you can add an optional argument that will perform value extraction, so you don't have to run a map on each array.

    var numbers = [
      1,
      2,
      3,
      4,
      5
    ]
    
    var people = [
      {
        name: 'Anna',
        age: 22
      },
      {
        name: 'Tom',
        age: 34
      }, {
        name: 'John',
        age: 12
      },
    ]
    
    var moreComplexObjects = [
      { 
        a: {
          b: {
            c: 6
          }
        }
      },
      { 
        a: {
          b: {
            c: 7
          }
        }
      },
      { 
        a: {
          b: {
            c: 8
          }
        }
      }
    ]
    
    //the default value of the second parameter is a function that returns the input
    let getAverage = (arr, valueExtractor = x => x) => { 
    
      //extract the value of each element
      let reducer = (total, currentValue) => total + valueExtractor(currentValue);
      let sum = arr.reduce(reducer, 0) //make sure you add an initialiser
      return sum / arr.length;
    }
    
    const ageExtractor = person => person.age;
    const complexKeyExtractor = obj => obj.a.b.c;
    
    console.log(getAverage(numbers));
    console.log(getAverage(people, ageExtractor));
    console.log(getAverage(moreComplexObjects, complexKeyExtractor));

    A note for the above, if you don't supply a second parameter to Array#reduce, then the first time it runs total will be the first element of the array, however the second time and onwards, it will be the sum so far. It's not worth handling that case, so supplying an initial value solves it.