Use the reduce Method to Analyze Data - Better Way with Arrow functions?

So I am trying to solidify my learning on arrow functions and working this problem:

https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/functional-programming/use-the-reduce-method-to-analyze-data/

My code works but is there a simpler way to get the length than what I have done in the arrow functions? Besides another variable?

const averageRating = watchList
  .filter(director => director.Director === "Christopher Nolan")
  .map(rating => parseFloat(parseFloat(rating.imdbRating).toFixed(1)))
  .reduce((accumulator, currentValue) => accumulator + currentValue, 0) / watchList
  .filter(director => director.Director === "Christopher Nolan")
  .map(rating => parseFloat(parseFloat(rating.imdbRating).toFixed(1))).length;

I think you can do it much simpler. Something like one reduce to get the total and one filter to get the total movies by Chris Nolan so that you can divide. In regards to your question specifically, I don’t think you need the last map to get the length.

Okay you’re right I don’t need that second map. While I can move each of these to their own variables…I was just hoping I didn’t have to if that makes sense.

another stab:

const nolan = watchList
  .filter(director => director.Director === "Christopher Nolan")

const averageRating = 
  nolan.map(rating => parseFloat(parseFloat(rating.imdbRating).toFixed(1)))
  .reduce((accumulator, currentValue) => accumulator + currentValue) / nolan.length;
1 Like

Optionally (I don’t really like the division in the reduce as it needs fairly tricky handling to avoid floating point errors):

const {total, count} = watchlist.reduce(({total, count}, {Director, imdbRating}) =>
 if (Director == "Christopher Nolan") {
   return {total + imdbRating, count + 1};
  } else {
  return {total, count};
  }
}, {total: 0, count: 0});

total / count;

That doesn’t seem to work. I thought Arrow functions didn’t accept if/else.

One of the main reasons arrow functions were included with ES6 is because they offer a shorter syntax(i.e. no function keyword) and especially in cases where the function is just a return statement (i.e. you can omit the typical blocks {} and the keyword return). These type of functions are present in other language, so, I guess JS doesn’t want to be left behind :slight_smile:.

However, using Arrow function you still have the option to use blocks/logic/different returns depending on logic etc, you just skip the function keyword and replace it with => I.e.

let testFN = (a,b) => {
    if (a > b) {return a - b} else {return a + b};
};

Dan’s suggestions has a minor mistake, it should work like that.

const {total, count} = watchList.reduce ( ({total, count} , {Director, imdbRating}) => {
    if (Director === "Christopher Nolan") {
        total += +imdbRating;
        count += 1;
        return {total, count};
    } else {
        return {total, count};
    }
}, {total : 0, count : 0});
console.log(total/count) //// 8.675

Hrm, okay that makes sense. Thanks!

Aside from the shorter syntax, they still have some other “peculiarities”, meaning that even in cases where you are not taking advantage of their option for a shorter syntax (i.e. you include logic etc.), you still might get “benefits” from their other “peculiarities” (i.e. they don’t get a local “this”, they get passed the “lexical this” of their environment).

They’re just a function, so you can put whatever in them. Doesn’t work because I missed the opening curly bracket off, I just saw the fix, it should have been

const {total, count} = watchlist.reduce(({total, count}, {Director, imdbRating}) => {
 if (Director == "Christopher Nolan") {
   return {total: total + imdbRating, count: count + 1};
  } else {
  return {total, count};
  }
}, {total: 0, count: 0});

Then the division

There is another approach (amongst many others):

function * filterMap (watchlist) {
  while (true) {
    const {Director, imdbRating} = watchlist.next();
    if (Director == "Christopher Nolan") yield imdbRating;
  }
}

function average(arrOfRatings) {
  return arrOfRatings.reduce((a, b) => a + b) / arrOfRatings.length;
}

average([...filterMap(watchlist)]);