# Functional Programming: Use the reduce Method to Analyze Data

Functional Programming: Use the reduce Method to Analyze Data
0
#1

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?

2 Likes
#2

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

``````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
#3

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')
``````
3 Likes
#4

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

#5

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 )
``````
2 Likes
#6

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?

#7

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
#8

Appreciate it! Thank you for the help.

split this topic #9

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

#10

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.

#11

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

#12
• converts strings to float value
#13

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;

1 Like
#14

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;
``````