Functional Programming - Use the reduce Method to Analyze Data

Im hoping for some clarification in understanding part of the solution to this challenge.

**THE TASK Use reduce to find the average IMDB rating of the movies directed by Christopher Nolan.

Here’s the line that Im having difficulties with:

.reduce((sumOfRatings, rating) => sumOfRatings + rating) 

My confusions stems from the fact that both rating and sumOfRatings is not defined anywhere in this challenge. I just dont understand their role in this solution.

let averageRating = watchList
.filter(x => x.Director("Christopher Nolan") == true)
.map(x => Number(x.idmbRating))
.reduce((sumOfRatings, rating) => sumOfRatings + rating) / watchList.filter(x => x.Director("Christopher Nolan").length;

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:106.0) Gecko/20100101 Firefox/106.0

Challenge: Functional Programming - Use the reduce Method to Analyze Data

Link to the challenge:

This is a function definition with two arguments.

That doesnt make sense.

Do you know what an arrow function is?

Do you know what obstruction means?

I’m aware what obstruction is.

That’s not what I’m doing here.

My explanation depends upon if you know what an arrow function is.

Oh. It’s you. My apologies. I’ll immediately stop trying to answer your question.

an arrow function is just a function written cleaner

Right, so with that in mind what type of thing are sumOfRatings and rating (in terms of general programming thing, not what their values are)?

in regards to this challenge? it appears they are just valueless argument placeholders. im not aware of them having any specific function in JS

They are simply function parameters, to which arguments will be passed to fulfil the reduce method. In this case, the reduce method iterates the array and reduces it to a single cumulative total of all of its elements. (Note that the preceding map method produces an array of the imdbRatings fields gleaned from each object in the main array).
The names given to the parameters are arbitrary (i.e. could be anything you choose). Makes sense though to choose names which accurately describe their purpose.

1 Like

So you’re saying that the reduce method produces the sum of what the .map function produced? the map method just produced a bunch of numbers. So when you apply reduce to a bunch of numbers, it just adds them all together?

No, reduce by definition runs a user-supplied function (in this case an accumulator) on each element in an array, returning a single value. In essence, it reduces all elements of an array to a single value, by whichever method you choose to define in the function.

The map method also runs a user-supplied function on each element of an array, producing a new array of elements modified by the function.

If you read up on the above links, it should explain it pretty well I think.

1 Like

I have a pretty good grasp of map. Unfortunately reduce syntax appears to be a different beast for me. After reading that link and comparing the notes I already have, I am no closer to understanding reduce syntax.

For now it appears that I will have to pray for a moment of clarity to obtain insight into how .reduce((sumOfRatings, rating) => sumOfRatings + rating) produces the sum of the imdbRatings. Im just not getting it.

The reduce method simply takes two parameters, an accumulator and the value of the current array index (e.g. sumOfRatings and rating). The method iterates the array, applying the user-supplied callback function to each index (e.g. rating) in turn, applying the result to the accumulator (e.g. sumOfRatings).

As, in this case, map has produced an array of imdbRatings values, the supplied callback function simply acts on this array by adding the value at each index (rating) to the accumulator (sumOfRatings), hence sumOfRatings + rating.

You could instead multiply or subtract or do any other manner of other operations instead, if you chose to supply a different callback function. You could also replace sumOfRatings and rating above with a and b or anything else you choose. The code will work regardless.

Fundamentally, the method is simply designed to iterate an array and reduce the whole array to a single value, by whichever means you chose. Essentially, it’s just done the legwork of the array iteration for you.

2 Likes

It doesn’t just “produce a bunch of numbers” and reduce doesn’t just “add them all together”. This is why I asked you about the function , whether you understood that they were arguments

If you’re saying you understand map, then you must understand that map is a function that you give an array + a callback function to. Then it runs that callback function on every element in the array. The callback function takes the current element, does {something} to it and returns that, like

function (element) {
  return /* Do something to the element */
}

Most of the array methods are exactly the same pattern, you give them an array and a function and they run that function on every element.

Reduce isn’t different, it’s not magic, you don’t have to pray for insight.

Map takes an array and returns that same array after it’s had the function ran for every element.

Reduce takes an array and a value (an accumulator), then returns that accumulator after it’s had the function ran for it and every element.

The callback function takes the value and the current element, does {something} involving both, and returns the result of that. When it runs on the next element, that result is the new value of accumulator, and so on.

Reduce takes two arguments: the first is the callback. The second is value you want to start the accumulator at. If you miss the second value out, reduce will use the first value in the array to start the accumulator

function (accumulator, element) {
  return /* result of doing something to both */
}

Like

function map(array, callback) {
  let outputArray = [];

  for (let i = 0; i < array.length; i++) {
    outputArray.push(callback(array[i]);
  }

  return outputArray;
}

function reduce(array, callback) {
  let accumulator = array[0]

  for (let i = 1; i < array.length; i++) {
    accumulator = callback(accumulator, array[i])
  }

  return accumulator;
}

console.log(map([1,2,3,4], (num) => num * 2))
// [2, 4, 6,]
console.log(reduce([1,2,3], (acc, num) => acc * num))
// 6
1 Like

I think you guys have triggered my moment of clarity. Let me see if I get this right.

The accumulator accumulated the results of what the filter and map function produced(the user supplied callback function).

And the element(rating) represents the individual elements in the array that the filter and map functions produced.

So the accumulator(sumOfRatings) + element(rating) produces the sum of each rating by adding each of one the individual elements that were produced by the filter and map functions. Correct?

So Im assuming that would also mean that accumulator(sumOfRatings) - element(rating) would subtract every element from the very first element, correct?

Thanks for your help guys, I couldn’t have done it without you.

Yes!
Pro tip: The accumulator by default takes an initial value equivalent to the first array element, unless you specify otherwise.

1 Like

OK so does that mean that this line (sumOfRatings, rating) => sumOfRatings + rating

can be rewritten as : (sumOfRatings, rating) => rating++; ?

No, because ++ is the increment operator. It simply adds one to the variable to which it is applied (as used in for loops for instance).