Demystifying map ,filter and reduce
map , filter and reduce are array methods or functions which are used to iterate over an array and perform certain operations such that they return an array which may or may not be same (but address will be different obviously).
Lets discuss map function
The map()
method of Array
instance creates a new array populated with the results of calling a provided function on every element in the calling array. Lets have a look at the code:
const array1 = [1, 4, 9, 16];
// Pass a function to map
//syntax is : array.map(callback function)
const map1 = array1.map((x) => x * 2);
/**
or can be seen as :
const map1=array1.map((x)=>{return(x*2)});
*/
console.log(map1);
// Expected output: Array [2, 8, 18, 32]
What is happening here is that we are going to iterate over each element of the array and call the callback function giving the element as parameter(there are other parameters as well which are sent) and keeping populating another array with the return values . You can paste the code in a JS file(lets say part1.js) and run it using:
node part1.js
You will see the expected output.
The other two parameters which are sent while calling the callback function: the index of the current element being iterated on and the original array.
const array1 = [1, 4, 9, 16];
const map1 = array1.map((x,index,arr) => x * 2 + index);
console.log(map1);
// Expected output: Array [2+0, 8+1, 18+2, 32+3]=[2,9,20,35]
I hope this was clear . This is a quite an important array function since its used a lot in React as well , though that time we would be returning JSX. Lets move to filter function.
Lets discuss filter function
The filter()
method of Array instance creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function. Lets have a look at the code:
const words = ['spray', 'elite', 'exuberant', 'destruction', 'present'];
//the callback function is supposed to return true or false for every
//word and if the return is true then the word will be filtered to the
//final array else not
const result = words.filter((word,index,arr) => word.length > 6);
console.log(result);
// Expected output: Array ["exuberant", "destruction", "present"]
You can run this and see the expected result. Nothing much to explain here and so lets move to the reduce function.
Let discuss reduce function
The reduce()
method of Array instance executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.
The first time that the callback is run there is no "return value of the previous calculation". If supplied, an initial value may be used in its place. Otherwise the array element at index 0 is used as the initial value and iteration starts from the next element (index 1 instead of index 0). Lets have a look at the code:
const array1 = [1, 2, 3, 4];
//we need to perform this operation: 0 + 1 + 2 + 3 + 4
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue, index, arr) => accumulator + currentValue,
initialValue,
);
console.log(sumWithInitial);
// Expected output: 10
What happens is first accumulator(lets say A) is 0 then iteration starts from the first element of the array , A becomes 0+1 for the next iteration .In the next iteration , A gets the value 0+1+2 for the following iteration .It occurs like this till the last iteration where the final value of A is returned as the value of the reduce function call.
If the initial value had not been given then the first element of the array had been used as the initial value of A and the iteration had begun from the second element of the array and the operation would have been like 1+2+3+4.
Lil bit complex but I am sure on going through it again it would be crystal clear. Lets look at the polyfills of the functions so that we can understand them in depth.
Lets discuss Polyfill of map function
Here we will be coding the map function from scratch. Lets see the code:
//using Array.prototype , we can add a custom array function of our own
Array.prototype.myMap=function (cb){
let temp=[];
for(let i=0;i<this.length;i++)//this refers to the specific array corresponding to which the
//myMap is used
{
temp.push(cb(this[i],i,this));//as you can see that while calling the
//callback function we are sending the current element,index,the original array
}
return temp;
}
console.log([1,2,3,4].myMap((x,i,arr)=>(x*2)));//[2,4,6,8]
You can run it and see the appropriate result. Just remember: Don't assign an arrow function to myMap then 'this' won't refer to the array being used.
Lets discuss the polyfill of filter function
Lets see the code:
//using Array.prototype , we can add a custom array function of our own
Array.prototype.myFilter=function (cb){
let temp=[];
for(let i=0;i<this.length;i++)
{
if(cb(this[i],i,this))
temp.push(this[i]);//whether we will take the element or not depends on the return
//value of cb function (it might return something other than true or false but we
//will take corresponding true or false equivalent , say 0/undefined/null means false)
}
return temp;
}
console.log([1,2,3,4].myFilter((x,i,arr)=>(x%2==0)));//[2,4]
Lets discuss Polyfill of reduce function
Lets look at the code:
//using Array.prototype , we can add a custom array function of our own
Array.prototype.myReduce=function (cb,initialValue){
let accumulator=initialValue;
for(let i=0;i<this.length;i++)
{
accumulator=accumulator?cb(accumulator,this[i],i,this):this[i];
//here one thing can happen is that the user may not give the value of the accumulator
//then what we do is simply check whether accumulator has got a value or not
//in case it doesn't then we simply give the first element as the inital value
//you will notice that for the next iterations there will anyways be a value for
//accumulator
}
return accumulator;
}
console.log([1,2,3,4].myReduce((accumulator,x,i,arr)=>(accumulator+x),0));//10
Lets discuss some interview questions
Difference between map and forEach
- map function will return an array when called but forEach won't return anything , it is a means to simply iterate over every element of the array. You can see it as a replacement of for look . Lets look at an equivalent forEach function for the map function we have discussed previously.
const arr1=[1,2,3,4];
//forEach won't be returning an array so we have to modify the original array
arr1.forEach((num,i,arr)=>{
arr1[i]*=2;
});
//lets print the modified original array
console.log(arr1);//[2,4,6,8]
Return only student names in uppercase
const array1=[
{name:"Mainak",position:"Left Wing",goals:2},
{name:"Rahul",position:"Centre Forward",goals:4},
{name:"Shyam",position:"Right Mid",goals:3}
];
//based on the above data, give the array of only student names in uppercase
//using for loop
let array2=[];
for(let i=0;i<array1.length;i++)
array2.push(array1[i].name.toUpperCase());
console.log(array2);
//using forEach
let array3=[];
array1.forEach((student)=>{array3.push(student.name.toUpperCase())});
console.log(array3);
//using map
console.log(array1.map((student)=>student.name.toUpperCase()));
Return students based on a condition
const array1=[
{name:"Mainak",position:"Left Wing",goals:2},
{name:"Rahul",position:"Centre Forward",goals:4},
{name:"Shyam",position:"Right Mid",goals:3},
{name:"Ram",position:"Centre Forward",goals:4}
];
//based on the above data, give the array of only those students who play "Centre Forward"
//and have scored more than 2 goals
//using for loop
let array2=[];
for(let i=0;i<array1.length;i++)
if(array1[i].position==="Centre Forward"&&array1[i].goals>2)
array2.push(array1[i]);
console.log(array2);
//using forEach
let array3=[];
array1.forEach((student)=>{
if(student.position==="Centre Forward"&&student.goals>2)
array3.push(student)
});
console.log(array3);
//using filter
console.log(array1.filter((student)=>(student.position==="Centre Forward"&&student.goals>2)));
Return total number of points
const array1=[
{name:"Mainak",position:"Left Wing",goals:2},
{name:"Rahul",position:"Centre Forward",goals:4},
{name:"Shyam",position:"Right Mid",goals:3},
{name:"Ram",position:"Centre Forward",goals:4}
];
//based on the above data, give the total number of goals scored by all of the students
//using for loop
let sum1=0;
for(let i=0;i<array1.length;i++)
sum1+=array1[i].goals;
console.log(sum1);
//using forEach
let sum2=0;
array1.forEach((student)=>{
sum2+=student.goals;
});
console.log(sum2);
//using reduce
console.log(array1.reduce((accumulator,student)=>(accumulator+student.goals),0));
Chaining
const array1=[
{name:"Mainak",position:"Left Wing",goals:2},
{name:"Rahul",position:"Centre Forward",goals:3},
{name:"Shyam",position:"Right Mid",goals:3},
{name:"Ram",position:"Centre Forward",goals:4}
];
//return the array of names of players such that they play "Centre Forward"
//filter will return an array and corresponding to it we can use a map function
console.log(array1.filter((student)=>(student.position==="Centre Forward")).map((forwardPlayer)=>(forwardPlayer.name)));
Wrapping Up
So thats it ! I hope you were able to understand the topics discussed in this blog . You can always refer to the official MDN Web Docs for further understanding .
Thank you for reading !