# Functional Programming: Use the reduce Method to Analyze Data

Hey guys!

I have a question about the FCC problem where you use the reduce method. Link below.
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/functional-programming/use-the-reduce-method-to-analyze-data/
It has an object containing multiple movies, and the challenge is to find the average score of Christopher Nolan movies.

The code I have is :

``````var averageRating = watchList
.filter(movie => {return movie.Director=="Christopher Nolan"})
.reduce((sum, nolanMovies) => {
return (sum + parseFloat(nolanMovies.imdbRating));
},0)
/(watchList.filter(movie => {return movie.Director=="Christopher Nolan"}).length);  // <--there has to be a better //way.
;
``````

while this works, I feel it is kind of ugly. As you can see, I could filter out the movie list and get the sum of the ratings but didnât know how to get the amount of movies there are without invoking the filter method again. I feel like there has to be a better way to do this but I just couldnât find out. What would be the best way so I can convert the sum of scores into an average?

3 Likes

You could increment your count while calculating sum if your accumulator could hold both values. Like an array [0,0] or an object {sum:0, count:0}. That would give you both numbers in one pass, maybe even calculate average at the end somehow.

EDIT
I figured this out. Maybe it will help you out.

``````const arr = [10,20,30];

const average = arr.reduce(function(acc,el,ind,ar){
acc = [acc[0]+el, acc[1]+1];
if(ind >= ar.length-1){  // calculate average on last element
acc = acc[0] / acc[1];
}
return acc;
},[0,0]);

console.log(average);  //20
``````
1 Like

You can first store the filtered array in a separate variable. That way you only have to do one `.filter()` call.

``````var moviesToRate = watchList.filter(...);
var averageRating = moviesToRate.reduce(...) / moviesToRate.length;
``````

Also note that when using arrow functions, if youâre immediately returning a new value, you can omit the braces and the `return` keyword altogether.

``````.filter(movie => movie.Director == 'Christopher Nolan')
``````
4 Likes

I like this, definitely more elegant than the way i have it. Thank you!

just completed this challenge, and here is a solution without in-processing variable

``````var averageRating;

averageRating = watchList
.filter( el => el.Director == "Christopher Nolan" )
.map( el => +el.imdbRating)
.reduce( (acc,cur,index) =>  (acc*index + cur) / (index + 1), 0 )
``````
3 Likes

Could someone help explain in more detail whatâs going on with the code below?

``````  .map( el => +el.imdbRating)
.reduce( (acc,cur,index) =>  (acc*index + cur) / (index + 1), 0 )
``````

In the map method, Iâm curious as to what the + does. For the reduce, Iâm just lost. What is acc and cur?

It coerces el.imbRating (a String value) to a number.

First, take a look at the documentation for reduce. If you have any questions about the documentation, let us know.

1 Like

Appreciate it! Thank you for the help.

A post was split to a new topic: Unable to pass the Use the reduce Method the Analyze Data challenge

Hi, can someone explain the meaning of (acc*index + cur)?
I created a separate array for each step: filter, map then reduce which provides the same answer. The âreduceâ method looks like this sum = Rating.reduce((total,item) => (total + parseFloat(item)/Rating.length),0)
So just want to understand how other solution works.
Thanks.

It is just an expression which multiplies the value of acc by the value of index and adds the value of cur.

• converts strings to float value

Mine is a bit more of simple, it doesnât use map or filter:

var movieCount = 0;
var averageRating = watchList.reduce(function(accumulator,currentValue){

if (currentValue.Director === âChristopher Nolanâ){
accumulator+= Number(currentValue.imdbRating);
movieCount++;
}

return accumulator;

},0)/ movieCount;

2 Likes

Thanks for the hint, I got it work like this:

``````var averageRating;

var moviesToRate = watchList.filter((movie) => movie.Director === 'Christopher Nolan');

averageRating = moviesToRate.map((movie) => Number(movie.imdbRating)).reduce((val1, val2) => (val1 + val2))/moviesToRate.length;
``````