Reduce() and accumulator question

Tell us what’s happening:

I’m slowly working my way through this challenge. I’m at the edge of finishing the last stage. My issue is (I think) that I’m not instantiating the accumulator correctly. In my mind, starting at the first number is logical. I add through all the numbers and divide by the length.

This does not work. I feel like I should pick something other than the first number as the instantiated acumulator. Am I right, wrong?

Your code so far

function getRating(watchList) {
let nolan = watchList.filter(film => film.Director === "Christopher Nolan");

let rate = nolan.map(({Title: title, imdbRating: rating})=> ({imdbRating: parseFloat(rating)}));

  // Only change code below this line
  let averageRating = rate.reduce((acc, cum)=> {acc+cum/rate.length}, rate[0]);


  // 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/96.0.4664.110 Safari/537.36

Challenge: Use the reduce Method to Analyze Data

Link to the challenge:

The math doesn’t work right if you use the first number. You need to take the average of all values in the array, so you need the sum of all values divided by the number of values. Your first number is not scaled by the number of values.

Isn’t it also going to use rate[0] twice? It is given as the initial condition, and then the first cum is going to be that same value. You could either give 0 for the initial or give no initial and then it will use the first element as the initial (but then you run into the same problem Jeremy mentioned). Another issue is that I don’t think your callback is returning anything.

1 Like

Don’t get frustrated. The reduce method is probably the most difficult method for new people to understand. It is actually quite simple and elegant, but until it “clicks” it seems so bizarre. Keep at it, you’ll get it.

1 Like

Okay. Still working on it. One issue is that the function, when console.logged, returns [object Object][object Object][object Object][object Object]
I don’t know understand how that’s coming back because I (think) I’ve defined everything. My suspicion is that my reduce() function is occluding the data, boxing it in through misuse of variables?
I feel like I’m talking out of my butt here, but that’s the only thing I could come up with.
I also made an empty array as the starter. It’s possible to build off that…but I’m not sure how I should take average. I thought of adding a counter into the reduce() function. It didn’t work on my first go around, but I’m still messing with it. A counter each time reduce goes through a cycle and divide the final sum by that.
Is that feasible?

function getRating(watchList) {

let nolan = watchList.filter(film => film.Director === "Christopher Nolan");

let rate = nolan.map(({Title: title, imdbRating: rating})=> ({imdbRating: parseFloat(rating)}));

console.log(rate)

  // Only change code below this line

 const averageRating = rate.reduce((ratings, rate)=> {return ratings+=rate}, []);

 

  // Only change code above this line

  return averageRating;

}

You are concatenating an array and an object. nolan is an array of objects and you set the initial value in the reduce to an empty array.

[] + {}
// '[object Object]'

You can log out ratings and rate inside the reduce to see it.


https://www.youtube.com/results?search_query=JS+reduce

I solved it. I understand it (I think), but I want to run through what I did.
I will do it below and please clarify or correct my logic where necessary:
Finding the average of movie ratings for Christopher Nolan movies in watchList array object:

[spoiler]
1. Use filter() to squeeze out only movies directed by Christopher Nolan.  This is done by using the element `film` to check each key entry of `Director` has the value `'Christopher Nolan'` (TRUE) or not (FALSE).
2. Establish the number of movies by 'Christopher Nolan' using `.length`
3. Use `map()` to structure the data so that it presents only the title of a movie and it's rating AND that the rating is a number and NOT a string.  This is done by specifying that the new array produced by `map()` contains the value of `imdbRating` transformed from a string to a number (using `ParseFloat()`)
4. `reduce()` is run on the new array produced by `map()` .  The initialized value is 0.   `total`is the accumulator.  This is increased with each subsequent review rating (indicated by `review`).  These are added together and the total sum is returned as `total`.
This total is divided  by the sum of Nolan movies in the object and this is the average.
[/spoiler]

Am I understanding what I did correctly? I feel pretty confident, but I want to be sure I’m not misunderstanding something that I did.

function getRating(watchList) {

  // Only change code below this line

//filter out Nolan movies

let nolan = watchList.filter(film => film.Director === "Christopher Nolan");

//find amount of Nolan movies

let nolanNum = nolan.length;

//map out title and ratings (with ratings converted into numbers from strings)

let rate = nolan.map(({Title: title, imdbRating: rating})=> ({imdbRating: parseFloat(rating)}));

console.log(rate)

//sum all Nolan ratings together

 let nolanSolution = rate.reduce((total, review)=> {total+=review.imdbRating; return total},0);

//average out ratings of Nolan movies

let averageRating = nolanSolution/nolanNum;

  // Only change code above this line

  return averageRating;

}
1 Like

Sure that works. Good work.

If you’re interested in tightening it up a bit, I wonder though, do you need the map? Couldn’t you deal with the numbers in the reduce?

And if you keep the map, why do you need the title? For that matter why do you need to save the elements as objects? Is there something that would make more sense for what we are trying to do?

1 Like

I was going to ask the same thing, I don’t see why you need the map. Anyway, if it works it works, so good job.

I might suggest you try to come up with some better variable names and I would personally use const instead of let.

1 Like