Reputation: 177
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/
Upvotes: 3
Views: 4907
Reputation: 792
More Simplified code
just execute as getAverage(people.map(p=> p.age)); using your code
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;
};
console.log(getAverage(people.map(p=> p.age)));
Upvotes: 1
Reputation: 16908
We can use Array.reduce
to compute the sum, where acc
is the accumulated sum and the individual objects are destructured to the age
variable then calculate the average by dividing the sum with the array length:
var people = [
{
name: 'Anna',
age: 22
},
{
name: 'Tom',
age: 34
}, {
name: 'John',
age: 12
},
];
function getAvg(arr){
return (people.reduce((acc, {age}) => (acc + age), 0))/arr.length;
}
console.log(getAvg(people));
We can also map the function to the age
property and calculate the sum by joining the array into a string and evaluating it inside the Function
constructor:
var people = [
{
name: 'Anna',
age: 22
},
{
name: 'Tom',
age: 34
}, {
name: 'John',
age: 12
},
];
function getAvg(arr){
return (new Function(`return ${people.map(({age}) => age).join("+")}`)()) / arr.length;
}
console.log(getAvg(people));
Upvotes: 2
Reputation: 28996
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.
Upvotes: 5
Reputation: 36574
You can use reduce()
and add property age
of each object in array to ac
. Don't forget to pass 0
(initial value of ac
) as second argument otherwise it would return NaN
var people = [
{
name: 'Anna',
age: 22
},
{
name: 'Tom',
age: 34
}, {
name: 'John',
age: 12
},
]
let avgs = people.reduce((ac,a) => a.age + ac,0)/people.length
console.log(avgs)
Upvotes: 4
Reputation: 386654
You could supply a function for the wanted property and reduce with a start value.
const
getAverage = (array, fn = v => v) => {
var reducer = fn => (total, item) => total + fn(item),
sum = array.reduce(reducer(fn), 0);
return sum / array.length;
};
var people = [{ name: 'Anna', age: 22 }, { name: 'Tom', age: 34 }, { name: 'John', age: 12 }];
console.log(getAverage(people, o => o.age));
Upvotes: 2