Trying to fix my reduce function

Tell us what’s happening:

I solved the challenge (although I see from the given solutions that I didn’t need to create so many variables). My question is I don’t understand why I couldn’t calculate the average rating with the reduce function doing this:

let addRatings = mappedMovies.reduce((a, val) => {
    return (a + val) / mappedMovies.length;
  })

To me, that looks like it’s doing the same thing Solution 1 is doing. But that returns a value of 2.9…
So that’s why I had to find the average in two steps; first adding all the ratings, then creating another function just to do the division.

Your code so far


function getRating(watchList){
  // Only change code below this line
  let nolanMovies = watchList.filter(nolan => {
    return nolan.Director === "Christopher Nolan"
  })
  let mappedMovies = nolanMovies.map(rating => {
    return parseFloat(rating["imdbRating"]) }
  )
  let addRatings = mappedMovies.reduce((a, val) => {
    return (a + val) 
  })

  var averageRating = addRatings / mappedMovies.length;
  
  // Only change code above this line
  return averageRating;
}
console.log(getRating(watchList));

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36.

Challenge: Use the reduce Method to Analyze Data

Link to the challenge:

Hi,

In the solution, we have

Notice that the division is outside of the reduce function. The average is (sum / length), but you were incrementally summing and dividing, which results in a very different calculation.

Edit, you can repair your accumulator function by only dividing the current value instead of the sum of the current value and the accumulator.

6 Likes

I’ve found that when I’m confused about a loop, getting some paper (or a spreadsheet) and writing down the value of every variable and operation for each loop usually clears it up.

In this case, this line:

return (a + val) / mappedMovies.length;

Means the accumulated sum (at that point) + the value of the current element are being divided by the total number of elements each iteration.

Whereas the right answer involves dividing the total ratings by the total number of ratings, right?

The problem (I think) is that in your code, you are dividing by the total number when the method has only added less than the total of items. It would be fine if mappedMovies.length changed with each iteration, but it doesn’t.

If you wanted to do it like this, I think you could divide it by using the callback function’s index parameter (google reduce() MDN for details), but honestly I think using the second line of code is more readable.

Not quite. You should divide by the true total, but you should not divide the accumulated value ‘again’

In math:

// 'Normal' calculation (From OP passing solution and Solution 1)
avg1 = (arr[0] + arr[1] + arr[2] + ... + arr[n-1]) / n;

// 'Incremental' calculation (Would fix OP's reduce)
avg2 = arr[0] / n + arr[1] / n + arr[2] / n + ... + arr[n-1] / n;

// Incorrect calculation (OP's slightly off reduce)
avg3 = (...((arr[0] / n + arr[1]) / n + arr[2]) / n + ... + arr[n-1]) / n;
1 Like

As always, thank you.

I can also connect the filter/map/reduce functions together so I’m not declaring multiple variables. I assume that’s preferable than what I did :slight_smile:

1 Like

In my opinion (Note: I’m not a JavaScript guy, I write mostly C), chaining filter/map/reduce should be done when clearer and more straightforward. But, more compact code is not automatically better code. And there are a million opinions about what patterns are more readable or maintainable.

freeCodeCamp had a good article talking about possible performance implications of chaning:

2 Likes

this is my solution :

function getRating(watchList){
  // Only change code below this line
  const filtered = watchList.filter(item => item.Director === 'Christopher Nolan');

  var averageRating = filtered.reduce((sum,element)=> sum +  +(element.imdbRating), 0);
  // Only change code above this line
  return averageRating / (filtered.length);
}
console.log(getRating(watchList));
1 Like

It is great that you solved the challenge, but instead of posting your full working solution, it is best to stay focused on answering the original poster’s question(s) and help guide them with hints and suggestions to solve their own issues with the challenge.

We are trying to cut back on the number of spoiler solutions found on the forum and instead focus on helping other campers with their questions and definitely not posting full working solutions.

You can post solutions that invite discussion (like asking how the solution works, or asking about certain parts of the solution). But please don’t just post your solution for the sake of sharing it.
If you post a full passing solution to a challenge and have questions about it, please surround it with [spoiler] and [/spoiler] tags on the line above and below your solution code.

2 Likes