If you’ve just started coding in JavaScript for a short while, you’ve probably only heard of .map()
, .reduce()
and .filter()
but haven’t really used it much. For me, it took a while because I code for a Japanese company . So I have to code how to be able to support Internet Explorer 8 and some older browsers (mainly the maintenance project, the rest is all ES6.). So if you don’t need to code something that needs to be compatible with these very old browsers, then you have to be familiar with functions like .map()
, .reduce()
and .filter()
it will help you a lot.
Opening example: this groupBy function is just a few simple lines and it is too convenient to group + filter If you go through this article, I think you can also code a function like that
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | <span class="token keyword">const</span> personnel <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Luke Skywalker"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">98</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">56</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">82</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Sabine Wren"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">73</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">99</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Zeb Orellios"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">59</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">15</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Ezra Bridger"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">43</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">67</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">11</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Caleb Dume"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">71</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">85</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token comment">/** * Hàm GroupBy theo hàm điều kiện * @param fnKey Điều kiện group by * @param fnValue Điều kiện filter cho mỗi kết quả * @param list List đầu vào * @returns Trả về 1 đối tượng */</span> <span class="token keyword">function</span> <span class="token function">groupBy</span> <span class="token punctuation">(</span> list <span class="token punctuation">,</span> fnKey <span class="token punctuation">,</span> <span class="token function-variable function">fnValue</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">e</span> <span class="token punctuation">)</span> <span class="token operator">=></span> e <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> list <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">prev <span class="token punctuation">,</span> next</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> <span class="token operator">...</span> prev <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token function">fnKey</span> <span class="token punctuation">(</span> next <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token operator">...</span> <span class="token punctuation">(</span> prev <span class="token punctuation">[</span> <span class="token function">fnKey</span> <span class="token punctuation">(</span> next <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token operator">||</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token function">fnValue</span> <span class="token punctuation">(</span> next <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token function">groupBy</span> <span class="token punctuation">(</span> personnel <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">e</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> isForceUser <span class="token operator">?</span> <span class="token string">"Force User"</span> <span class="token operator">:</span> <span class="token string">"Not Force User"</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token parameter">e</span> <span class="token punctuation">)</span> <span class="token operator">=></span> e <span class="token punctuation">.</span> name <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Result: Another special feature is that the difficulty of this algorithm is (On)
too good
1 2 3 4 5 | <span class="token punctuation">{</span> <span class="token string">'Force User'</span> <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'Luke Skywalker'</span> <span class="token punctuation">,</span> <span class="token string">'Ezra Bridger'</span> <span class="token punctuation">,</span> <span class="token string">'Caleb Dume'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token string">'Not Force User'</span> <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token string">'Sabine Wren'</span> <span class="token punctuation">,</span> <span class="token string">'Zeb Orellios'</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> |
Note that this article will most likely apply to any other programming language you may be using, as these are concepts that exist in many other languages.
OK HATE
.map()
Let me explain how it works with a simple example. Let’s say you received an array containing many objects – each object represents a person. However, what you really need in the end is an array containing only the id of each person.
1 2 3 4 5 6 7 8 9 10 | <span class="token comment">// Những gì bạn có </span> <span class="token keyword">var</span> officers <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Captain Piett'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">24</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'General Veers'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">56</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Admiral Ozzel'</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">88</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Commander Jerjerrod'</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token comment">// Thứ bạn cần </span> <span class="token punctuation">[</span> <span class="token number">20</span> <span class="token punctuation">,</span> <span class="token number">24</span> <span class="token punctuation">,</span> <span class="token number">56</span> <span class="token punctuation">,</span> <span class="token number">88</span> <span class="token punctuation">]</span> |
There are many ways to achieve this. You might want to do that by creating an empty array, then using .forEach()
, .for(...of)
or simply .for()
to achieve your purpose.
Let’s compare ways to do it!
Using .forEach()
:
1 2 3 4 5 | <span class="token keyword">var</span> officersIds <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> officers <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">officer</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> officersIds <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> officer <span class="token punctuation">.</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Notice this way you have to create an empty array first? Next, let’s see what it looks like using .map()
:
1 2 3 4 5 | <span class="token keyword">var</span> officersIds <span class="token operator">=</span> officers <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">officer</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> officer <span class="token punctuation">.</span> id <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
We can be even more concise with arrow functions (Note: ES6, Babel or TypeScript)
1 2 | <span class="token keyword">const</span> officersIds <span class="token operator">=</span> officers <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">officer</span> <span class="token operator">=></span> officer <span class="token punctuation">.</span> id <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
So how does .map()
work? Basically there are 2 arguments, a callback function and an optional contexts (default will be this
in the callback function) that I didn’t use in the previous example. The callback function will be called for each value in the array and return each new value in the resulting array.
Remember that the resulting array will always be the same length as the original array.
.reduce()
Like .map()
, .reduce()
also calls the callback function for each element of the array. What’s different here is that reduce
passes the result of this callback to an bộ tích lũy
from one array element to another.
The accumulator can be anything (integer, string, object, etc) and must be initialized or passed in when .reduce()
called.
Time to do some examples to make it easier to understand! Let’s say you have a list of pilots and their respective years of experience:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">var</span> pilots <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">10</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Poe Dameron"</span> <span class="token punctuation">,</span> years <span class="token operator">:</span> <span class="token number">14</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Temmin 'Snap' Wexley"</span> <span class="token punctuation">,</span> years <span class="token operator">:</span> <span class="token number">30</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">41</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Tallissan Lintra"</span> <span class="token punctuation">,</span> years <span class="token operator">:</span> <span class="token number">16</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">99</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Ello Asty"</span> <span class="token punctuation">,</span> years <span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> |
We need to know the total years of experience of all of them. With .reduce()
, it’s pretty simple:
1 2 3 4 | <span class="token keyword">var</span> totalYears <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">accumulator <span class="token punctuation">,</span> pilot</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> accumulator <span class="token operator">+</span> pilot <span class="token punctuation">.</span> years <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Note that I have set the starting value
to 0
. I can also use an object if needed. After calling the callback for each element of the array, reduce will return the final value of our bộ tích lũy
(in this case: 82
).
And of course it can also be shortened with ES6 arrow functions:
1 2 | <span class="token keyword">const</span> totalYears <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">acc <span class="token punctuation">,</span> pilot</span> <span class="token punctuation">)</span> <span class="token operator">=></span> acc <span class="token operator">+</span> pilot <span class="token punctuation">.</span> years <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Now, suppose we want to find out which pilot is the most experienced. For this question, I could also use reduce
:
1 2 3 4 | <span class="token keyword">var</span> mostExpPilot <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">oldest <span class="token punctuation">,</span> pilot</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> oldest <span class="token punctuation">.</span> years <span class="token operator">||</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token operator">></span> pilot <span class="token punctuation">.</span> years <span class="token operator">?</span> oldest <span class="token operator">:</span> pilot <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
I named my bộ tích lũy
oldest
. My callback function compares the accumulator with each pilot. If a pilot has more years of experience than oldest
, then that pilot will become the oldest
pilot and eventually I will return oldest
.
As you can see, using .reduce()
is an easy way to create a value
or an Object
from an array.
.filter()
What if you have an array, but only want some elements in it? That’s when you need to use .filter()
Here is our data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">var</span> pilots <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">2</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Wedge Antilles"</span> <span class="token punctuation">,</span> faction <span class="token operator">:</span> <span class="token string">"Rebels"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">8</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Ciena Ree"</span> <span class="token punctuation">,</span> faction <span class="token operator">:</span> <span class="token string">"Empire"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">40</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Iden Versio"</span> <span class="token punctuation">,</span> faction <span class="token operator">:</span> <span class="token string">"Empire"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">66</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Thane Kyrell"</span> <span class="token punctuation">,</span> faction <span class="token operator">:</span> <span class="token string">"Rebels"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> |
Suppose now we want to have two arrays: one is for the “Rebels”, the other is for the “Empire” piece. With .filter()
it’s simply useless!
1 2 3 4 5 6 7 | <span class="token keyword">var</span> rebels <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">pilot</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> pilot <span class="token punctuation">.</span> faction <span class="token operator">===</span> <span class="token string">"Rebels"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">var</span> empire <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">pilot</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> pilot <span class="token punctuation">.</span> faction <span class="token operator">===</span> <span class="token string">"Empire"</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
And it’s even shorter with arrow functions:
1 2 3 | <span class="token keyword">const</span> rebels <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token parameter">pilot</span> <span class="token operator">=></span> pilot <span class="token punctuation">.</span> faction <span class="token operator">===</span> <span class="token string">"Rebels"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> empire <span class="token operator">=</span> pilots <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token parameter">pilot</span> <span class="token operator">=></span> pilot <span class="token punctuation">.</span> faction <span class="token operator">===</span> <span class="token string">"Empire"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Basically, if the callback function returns true , the current element will be in the resulting array . If it returns false
, it will not be included in the results list.
Go to the good part about combining .map(), .reduce() and .filter()
Since all three are called on arrays, and since .map()
and .filter()
both return arrays, we can easily chain our calls.
Let’s see another example. Here is our data:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token keyword">var</span> personnel <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">5</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Luke Skywalker"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">98</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">56</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">82</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Sabine Wren"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">73</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">99</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">22</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Zeb Orellios"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">20</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">59</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">15</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Ezra Bridger"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">43</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">67</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token number">11</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"Caleb Dume"</span> <span class="token punctuation">,</span> pilotingScore <span class="token operator">:</span> <span class="token number">71</span> <span class="token punctuation">,</span> shootingScore <span class="token operator">:</span> <span class="token number">85</span> <span class="token punctuation">,</span> isForceUser <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> |
Our goal is: just get the total score of the users whose isForceUser
is true
. Let’s do it step by step!
First, we need to filter out the user
for which isForceUser
is false
:
1 2 3 4 5 | <span class="token keyword">var</span> jediPersonnel <span class="token operator">=</span> personnel <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">person</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> person <span class="token punctuation">.</span> isForceUser <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Result: [{...}, {...}, {...}] (Luke, Ezra and Caleb)</span> |
After filtering, we have 3 elements left in our resulting array. Now we need to create an array containing the total score of each Jedi
.
1 2 3 4 5 | <span class="token keyword">var</span> jediScores <span class="token operator">=</span> jediPersonnel <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">jedi</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> jedi <span class="token punctuation">.</span> pilotingScore <span class="token operator">+</span> jedi <span class="token punctuation">.</span> shootingScore <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Result: [154, 110, 156]</span> |
And let’s use reduce
to get the total:
1 2 3 4 5 | <span class="token keyword">var</span> totalJediScore <span class="token operator">=</span> jediScores <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">acc <span class="token punctuation">,</span> score</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> acc <span class="token operator">+</span> score <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Result: 420</span> |
And now the fun part… we can chain all of this to get what we want in a single line:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">var</span> totalJediScore <span class="token operator">=</span> personnel <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">person</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> person <span class="token punctuation">.</span> isForceUser <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">jedi</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> jedi <span class="token punctuation">.</span> pilotingScore <span class="token operator">+</span> jedi <span class="token punctuation">.</span> shootingScore <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">acc <span class="token punctuation">,</span> score</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> acc <span class="token operator">+</span> score <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
And see how concise it is if used with arrow functions:
1 2 3 4 5 | <span class="token keyword">const</span> totalJediScore <span class="token operator">=</span> personnel <span class="token punctuation">.</span> <span class="token function">filter</span> <span class="token punctuation">(</span> <span class="token parameter">person</span> <span class="token operator">=></span> person <span class="token punctuation">.</span> isForceUser <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> <span class="token parameter">jedi</span> <span class="token operator">=></span> jedi <span class="token punctuation">.</span> pilotingScore <span class="token operator">+</span> jedi <span class="token punctuation">.</span> shootingScore <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">acc <span class="token punctuation">,</span> score</span> <span class="token punctuation">)</span> <span class="token operator">=></span> acc <span class="token operator">+</span> score <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Boom! It’s so cool, isn’t it much easier to understand in a shorter way
Note: In the above example, .map()
and .filter()
are not even needed. We can easily achieve the same result with just .reduce()
. However, in the above example, I still use it for you to better visualize. Can you guess how just using .reduce()
and still get the same result with just one line of code?
Ten ten easy is right:
1 2 3 4 5 6 7 8 | <span class="token keyword">const</span> totalJediScore <span class="token operator">=</span> personnel <span class="token punctuation">.</span> <span class="token function">reduce</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">acc <span class="token punctuation">,</span> person</span> <span class="token punctuation">)</span> <span class="token operator">=></span> person <span class="token punctuation">.</span> isForceUser <span class="token operator">?</span> acc <span class="token operator">+</span> person <span class="token punctuation">.</span> pilotingScore <span class="token operator">+</span> person <span class="token punctuation">.</span> shootingScore <span class="token operator">:</span> acc <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Why not use .forEach()?
Great question, actually I used to use for
loops everywhere instead of .map()
, .reduce()
and .filter()
. But recently, when I had the opportunity to write the function bases myself for my current project, I started working more with the data coming from the API. That’s when I started to see the advantages of using them. As you can see in the first example I gave, you can completely solve a problem with just 1 line of code.
Formatting
Let’s say you have a list containing name
and title
:
1 2 3 4 5 6 7 8 9 10 11 | <span class="token keyword">var</span> data <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Jan Dodonna"</span> <span class="token punctuation">,</span> title <span class="token operator">:</span> <span class="token string">"General"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> name <span class="token operator">:</span> <span class="token string">"Gial Ackbar"</span> <span class="token punctuation">,</span> title <span class="token operator">:</span> <span class="token string">"Admiral"</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> |
The API gives you the above data, but you only need the title and last name of each person… Since we have the fullname, we must format it right? (firstname + lastname) So you have to write a data format function to use every time we loop.
That means you can’t have a .forEach
loop inside the formatElement
function, otherwise you’ll have to wrap your single element in an array before passing it to the function just for it to work, like this:
1 2 3 | <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token function">formatElement</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> element <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token comment">// Yeah... điều đó không đúng chút nào</span> |
So your loop must end the call of the function, like this:
1 2 3 4 5 | data <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">element</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> formatted <span class="token operator">=</span> <span class="token function">formatElement</span> <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Nhưng sau đó thì sao.... </span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
But .forEach()
doesn’t return anything. That means you have to push the result inside a pre-declared array.
1 2 3 4 5 6 | <span class="token keyword">var</span> results <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> data <span class="token punctuation">.</span> <span class="token function">forEach</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">element</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> formatted <span class="token operator">=</span> <span class="token function">formatElement</span> <span class="token punctuation">(</span> element <span class="token punctuation">)</span> <span class="token punctuation">;</span> results <span class="token punctuation">.</span> <span class="token function">push</span> <span class="token punctuation">(</span> formatted <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
As a result you have 2 functions: the formatElement()
function and the function that push
the result into your array.
Why have 2 functions when you only need 1 is enough:
1 2 | <span class="token keyword">var</span> results <span class="token operator">=</span> data <span class="token punctuation">.</span> <span class="token function">map</span> <span class="token punctuation">(</span> formatElement <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Testing is easier
If you write unit tests for your code, you will find it simpler to test functions with .map()
, .reduce()
or .filter()
.
All you have to do is feed the function data and expect the results to appear. Basically “what if this is passed
?”. Fewer operations, less beforeEach()
and afterEach()
. It will be a lot simpler.
Try to replace some of your for
loops with .map()
, .reduce()
, .filter()
where it seems appropriate. I guarantee your code will be less cluttered and much easier to read.
In the past, when I first used these functions, especially .reduce()
, I was also very confused but gradually I will get used to it.
Roundup
As always, I hope you enjoyed this article and learned something new.
Thank you and see you in the next posts!
If you find this blog interesting, please give me a like and subscribe to support me. Thank you.