ES2019 introduces the Array.prototype.flatMap method. In this lesson, we'll investigate a common use case for mapping and filtering an array in a single iteration. We'll then see how to do this using Array.prototype.reduce, and then refactor the code to do the same thing using the ES2019 .flatMap method.
Instructor: [00:00] Once again, we're looking at our next JS application. This time, we're looking at a filtered average or students per session. I can click on A or B and get different filtered average, which is the average number of students that attended a session by that site. If we again look at our JSON, we see that each site has an ID. We can look at the averages for A or B by filtering them.
[00:24] We look at our sites.vue file. We see that the filtered average is the filtered average count property, which is again a computed property based off of our records. Whereas before we were flat mapping or we just pulled AM and PM off of every record, in this case we wanted to do something different.
[00:41] Prior to ES2019, once again, we didn't have flatMap function. We would use a foreach and push elements onto an array that we would aggregate ourselves. In this case, we compare the ID of the record and see if it's equivalent to the ID property that we set in Nuxt.js.
[01:00] Again, when you click on each of the IDs, you see that we're setting the ID property equal to the site ID that we're clicking on. This ID is the ID that we're filtering. Record.ID is the ID of the record. Only in the case where the IDs match do we push the records AM and PM value onto our overall list of numbers to be averaged.
[01:23] We can convert this to flatMap too. Again, we could say const ounce = this.records.flatMap. Here's the cool part about flatMap. If you pass back an empty array, it'll push nothing onto the stack of averages to be counted. If I save this now, we'd see that it's going to do a zero over zero, which is NaN.
[01:48] In this case we wanted to do our condition from before. We want to say, "If the IDs match, then we could return record AM and PM. If IDs don't match, just return an empty array." If we run this again, we'll see that we now get the functionality that we had before.
[02:16] Let's look at this again. The first time, flatMap is the first function that actually in JavaScript allows us to both map and filter at the same time. If you're using a filter function, if you were doing records.filter in JavaScript, you only get a chance to either include or exclude a record.
[02:35] You would have to do something like return this record ID equals that record ID. This will just either include or exclude the record. If you do a map, map allows you to turn those objects into arrays, but there's nothing in ES pre-2019 that allows you to both filter and map.
[02:57] That's where I think flatMap is pretty cool. It allows you to pass back an array of records, or it allows you to pass back an empty array and say, "You know what? Don't give me any values from this record." Again, if we save this and run it, we've achieved the same functionality as before.
Hi Stephen,
Thanks for the feedback. You can certainly do that! To me, it's all about whatever is clearest for you and your team. In this case, I personally prefer the ternary, and in the case when working with large arrays, I'd prefer to do one iteration via flatMap
rather than 2 iterations via filter
and flatMap
.
reduce
is what I used to perform algorithms like this before but flatMap
is a great alternative!
See my comments on the previous video, haha—they all apply here as well (except that the counts
declaration in the transcript has been fixed). I watched through these videos once already, so this one must have been in the back of my mind.
Seem like chaining filter then flatmap would be clearer? const counts = this.records.filter(record => this.id === record.id).flatMap(record => [record.am, record.pm]); IMO this is more explicit that you are filtering rather than the ternary