Skip to content

map, filter & reduce

map, filter & reducer are Higher Order Functions.

flowchart LR
subgraph Input["Input Array"]
Arr["[5, 1, 3, 2, 6]"]
end
subgraph Map["map"]
MapDesc["Transform each element
Returns NEW array (same length)"]
MapEx["map(double) -> [10, 2, 6, 4, 12]
map(binary) -> ['101', '1', '11', '10', '110']"]
end
subgraph Filter["filter"]
FilterDesc["Keep elements passing test
Returns NEW array (<= length)"]
FilterEx["filter(isOdd) -> [5, 1, 3]
filter(n > 2) -> [5, 3, 6]"]
end
subgraph Reduce["reduce"]
ReduceDesc["Accumulate to single value
Returns ATOMIC value"]
ReduceEx["reduce(sum) -> 17
reduce(max) -> 6
reduce(groupBy) -> {29: 2, 50: 1}"]
end
Arr --> Map
Arr --> Filter
Arr --> Reduce
style Input fill:#1e293b,color:#fff
style Arr fill:#7c3aed,color:#fff
style Map fill:#4f46e5,color:#fff
style Filter fill:#6366f1,color:#fff
style Reduce fill:#059669,color:#fff

It is basically used to transform a array. The map() method creates a new array with the results of calling a function for every array element.

const output = arr.map(function) // this function tells map that what transformation I want on each element of array

const arr = [5, 1, 3, 2, 6];
// Task 1: Double the array element: [10, 2, 6, 4, 12]
function double(x) {
return x * 2;
}
const doubleArr = arr.map(double); // Internally map will run double function for each element of array and create a new array and returns it.
console.log(doubleArr); // [10, 2, 6, 4, 12]
// Task 2: Triple the array element
const arr = [5, 1, 3, 2, 6];
// Transformation logic
function triple(x) {
return x * 3;
}
const tripleArr = arr.map(triple);
console.log(tripleArr); // [15, 3, 9, 6, 18]
// Task 3: Convert array elements to binary
const arr = [5, 1, 3, 2, 6];
// Transformation logic:
function binary(x) {
return x.toString(2);
}
const binaryArr = arr.map(binary);
// The above code can be rewritten as :
const binaryArr = arr.map(function binary(x) {
return x.toString(2);
}
// OR -> Arrow function
const binaryArr = arr.map((x) => x.toString(2));

So basically map function is mapping each and every value and transforming it based on given condition.

Filter function is basically used to filter the value inside an array. The arr.filter() method is used to create a new array from a given array consisting of only those elements from the given array which satisfy a condition set by the argument method.

const array = [5, 1, 3, 2, 6];
// filter odd values
function isOdd(x) {
return x % 2;
}
const oddArr = array.filter(isOdd); // [5,1,3]
// Other way of writing the above:
const oddArr = arr.filter((x) => x % 2);

Filter function creates an array and store only those values which evaluates to true.

It is a function which take all the values of array and gives a single output of it. It reduces the array to give a single output.

const array = [5, 1, 3, 2, 6];
// Calculate sum of elements of array - Non functional programming way
function findSum(arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum = sum + arr[i];
}
return sum;
}
console.log(findSum(array)); // 17
// reduce function way
const sumOfElem = arr.reduce(function (accumulator, current) {
// current represent the value of array
// accumulator is used the result from element of array.
// In comparison to previous code snippet, *sum* variable is *accumulator* and *arr[i]* is *current*
accumulator = accumulator + current;
return accumulator;
}, 0); //In above example sum was initialized with 0, so over here accumulator also needs to be initialized, so the second argument to reduce function represent the initialization value.
console.log(sumOfElem); // 17
// find max inside array: Non functional programming way:
const array = [5, 1, 3, 2, 6];
function findMax(arr) {
let max = 0;
for(let i = 0; i < arr.length; i++ {
if (arr[i] > max) {
max = arr[i]
}
}
return max;
}
console.log(findMax(array)); // 6
// using reduce
const output = arr.reduce((acc, current) => {
if (current > acc ) {
acc = current;
}
return acc;
}, 0);
console.log(output); // 6
// acc is just a label which represent the accumulated value till now,
// so we can also label it as max in this case
const output = arr.reduce((max, current) => {
if (current > max) {
max= current;
}
return max;
}, 0);
console.log(output); // 6
const users = [
{ firstName: "Alok", lastName: "Raj", age: 23 },
{ firstName: "Ashish", lastName: "Kumar", age: 29 },
{ firstName: "Ankit", lastName: "Roy", age: 29 },
{ firstName: "Pranav", lastName: "Mukherjee", age: 50 },
];
// Get array of full name : ["Alok Raj", "Ashish Kumar", ...]
const fullNameArr = users.map((user) => user.firstName + " " + user.lastName);
console.log(fullNameArr); // ["Alok Raj", "Ashish Kumar", ...]
----------------------------------------------------------
// Get the count/report of how many unique people with unique age are there
// like: {29 : 2, 75 : 1, 50 : 1}
// We should use reduce, why? we want to deduce some information from the array. Basically we want to get a single object as output
const report = users.reduce((acc, curr) => {
if(acc[curr.age]) {
acc[curr.age] = ++ acc[curr.age] ;
} else {
acc[curr.age] = 1;
}
return acc; //to every time return update object
}, {})
console.log(report) // {29 : 2, 75 : 1, 50 : 1}
// First name of all people whose age is less than 30
const users = [
{ firstName: "Alok", lastName: "Raj", age: 23 },
{ firstName: "Ashish", lastName: "Kumar", age: 29 },
{ firstName: "Ankit", lastName: "Roy", age: 29 },
{ firstName: "Pranav", lastName: "Mukherjee", age: 50 },
];
// function chaining
const output = users
.filter((user) => user.age < 30)
.map((user) => user.firstName);
console.log(output); // ["Alok", "Ashish", "Ankit"]
// Homework challenge: Implement the same logic using reduce
const output = users.reduce((acc, curr) => {
if (curr.age < 30) {
acc.push(curr.firstName);
}
return acc;
}, []);
console.log(output); // ["Alok", "Ashish", "Ankit"]

Watch Live On Youtube below:

map, filter & reduce Youtube Link




Episode 20 (Season 2 : Episode 1) : Callback

Section titled “Episode 20 (Season 2 : Episode 1) : Callback”
flowchart TD
Create["api.createOrder(cart)"] --> Payment["api.proceedToPayment()"]
Payment --> Summary["api.showOrderSummary()"]
Summary --> Wallet["api.updateWallet()"]
subgraph CallbackHell["Callback Hell (Pyramid of Doom)"]
CH["api.createOrder(cart, function() {
api.proceedToPayment(function() {
api.showOrderSummary(function() {
api.updateWallet(function() {
// Deep nesting!
})
})
})
})"]
end
subgraph PromiseChain["Promise Chaining (Clean)"]
PC["createOrder(cart)
.then(orderId => proceedToPayment(orderId))
.then(paymentInfo => showOrderSummary(paymentInfo))
.then(balance => updateWallet(balance))
.catch(err => console.log(err))"]
end
CallbackHell -.->|"Refactor"| PromiseChain
style CallbackHell fill:#dc2626,color:#fff
style PromiseChain fill:#059669,color:#fff
style Create fill:#4f46e5,color:#fff
style Payment fill:#4f46e5,color:#fff
style Summary fill:#4f46e5,color:#fff
style Wallet fill:#4f46e5,color:#fff
  • There are 2 Parts of Callback:

    1. Good Part of callback - Callback are super important while writing asynchronous code in JS
    2. Bad Part of Callback - Using callback we can face issue:
      • Callback Hell
      • Inversion of control
  • Understanding of Bad part of callback is super important to learn Promise in next lecture.

💡 JavaScript is synchronous, single threaded language. It can Just do one thing at a time, it has just one call-stack and it can execute one thing at a time. Whatever code we give to Javascript will be quickly executed by Javascript engine, it does not wait.

console.log("Namaste");
console.log("JavaScript");
console.log("Season 2");
// Namaste
// JavaScript
// Season 2
// 💡 It is quickly printing because `Time, tide & Javascript waits for none.`

But what if we have to delay execution of any line, we could utilize callback, How?

console.log("Namaste");
setTimeout(function () {
console.log("JavaScript");
}, 5000);
console.log("Season 2");
// Namaste
// Season 2
// JavaScript
// 💡 Here we are delaying the execution using callback approach of setTimeout.

Assume a scenario of e-Commerce web, where one user is placing order, he has added items like, shoes, pants and kurta in cart and now he is placing order. So in backend the situation could look something like this.

const cart = ["shoes", "pants", "kurta"];
// Two steps to place a order
// 1. Create a Order
// 2. Proceed to Payment
// It could look something like this:
api.createOrder();
api.proceedToPayment();

Assumption, once order is created then only we can proceed to payment, so there is a dependency. So How to manage this dependency. Callback can come as rescue, How?

api.createOrder(cart, function () {
api.proceedToPayment();
});
// 💡 Over here `createOrder` api is first creating a order then it is responsible to call `api.proceedToPayment()` as part of callback approach.

To make it a bit complicated, what if after payment is done, you have to show Order summary by calling api.showOrderSummary() and now it has dependency on api.proceedToPayment() Now my code should look something like this:

api.createOrder(cart, function () {
api.proceedToPayment(function () {
api.showOrderSummary();
});
});

Now what if we have to update the wallet, now this will have a dependency over showOrderSummary

api.createOrder(cart, function () {
api.proceedToPayment(function () {
api.showOrderSummary(function () {
api.updateWallet();
});
});
});
// 💡 Callback Hell

When we have a large codebase and multiple apis and have dependency on each other, then we fall into callback hell. These codes are tough to maintain. These callback hell structure is also known as Pyramid of Doom.

Till this point we are comfortable with concept of callback hell but now lets discuss about Inversion of Control. It is very important to understand in order to get comfortable around the concept of promise.

💡 Inversion of control is like that you lose the control of code when we are using callback.

Let’s understand with the help of example code and comments:

api.createOrder(cart, function () {
api.proceedToPayment();
});
// 💡 So over here, we are creating a order and then we are blindly trusting `createOrder` to call `proceedToPayment`.
// 💡 It is risky, as `proceedToPayment` is important part of code and we are blindly trusting `createOrder` to call it and handle it.
// 💡 When we pass a function as a callback, basically we are dependant on our parent function that it is his responsibility to run that function. This is called `inversion of control` because we are dependant on that function. What if parent function stopped working, what if it was developed by another programmer or callback runs two times or never run at all.
// 💡 In next session, we will see how we can fix such problems.

💡 Async programming in JavaScript exists because callback exits.

more at http://callbackhell.com/

Watch Live On Youtube below:

map, filter & reduce Youtube Link



Episode 21 (Season 2 : Episode 2) : Promises

Section titled “Episode 21 (Season 2 : Episode 2) : Promises”
flowchart LR
Pending["PENDING
Initial state"]
Pending -->|"resolve(value)"| Fulfilled["FULFILLED
.then() runs"]
Pending -->|"reject(error)"| Rejected["REJECTED
.catch() runs"]
Fulfilled --> Settled["SETTLED
.finally() runs"]
Rejected --> Settled
style Pending fill:#d97706,color:#fff
style Fulfilled fill:#059669,color:#fff
style Rejected fill:#dc2626,color:#fff
style Settled fill:#6366f1,color:#fff

Promises are used to handle async operations in JavaScript.

We will discuss with code example that how things used to work before Promises and then how it works after Promises

Suppose, taking an example of E-Commerce

const cart = ["shoes", "pants", "kurta"];
// Below two functions are asynchronous and dependent on each other
const orderId = createOrder(cart);
proceedToPayment(orderId);
// with Callback (Before Promise)
// Below here, it is the responsibility of createOrder function to first create the order then call the callback function
createOrder(cart, function () {
proceedToPayment(orderId);
});
// Above there is the issue of `Inversion of Control`

Q: How to fix the above issue?
A: Using Promise.

Now, we will make createOrder function return a promise and we will capture that promise into a variable

Promise is nothing but we can assume it to be empty object with some data value in it, and this data value will hold whatever this createOrder function will return.

Since createOrder function is an async function and we don’t know how much time will it take to finish execution.

So the moment createOrder will get executed, it will return you a undefined value. Let’s say after 5 secs execution finished so now orderId is ready so, it will fill the undefined value with the orderId.

In short, When createOrder get executed, it immediately returns a promise object with undefined value. then javascript will continue to execute with other lines of code. After sometime when createOrder has finished execution and orderId is ready then that will automatically be assigned to our returned promise which was earlier undefined.

Q: Question is how we will get to know response is ready?
A: So, we will attach a callback function to the promise object using then to get triggered automatically when result is ready.

const cart = ["shoes", "pants", "kurta"];
const promiseRef = createOrder(cart);
// this promiseRef has access to `then`
// {data: undefined}
// Initially it will be undefined so below code won't trigger
// After some time, when execution has finished and promiseRef has the data then automatically the below line will get triggered.
promiseRef.then(function () {
proceedToPayment(orderId);
});

Q: How it is better than callback approach?

In Earlier solution we used to pass the function and then used to trust the function to execute the callback.

But with promise, we are attaching a callback function to a promiseObject.

There is difference between these words, passing a function and attaching a function.

Promise guarantee, it will callback the attached function once it has the fulfilled data. And it will call it only once. Just once.

Earlier we talked about promise are object with empty data but that’s not entirely true, Promise are much more than that.

Now let’s understand and see a real promise object.

fetch is a web-api which is utilized to make api call and it returns a promise.

We will be calling public github api to fetch data https://api.github.com/users/alok722

// We will be calling public github api to fetch data
const URL = "https://api.github.com/users/alok722";
const user = fetch(URL);
// User above will be a promise.
console.log(user); // Promise {<Pending>}
/** OBSERVATIONS:
* If we will deep dive and see, this `promise` object has 3 things
* `prototype`, `promiseState` & `promiseResult`
* & this `promiseResult` is the same data which we talked earlier as data
* & initially `promiseResult` is `undefined`
*
* `promiseResult` will store data returned from API call
* `promiseState` will tell in which state the promise is currently, initially it will be in `pending` state and later it will become `fulfilled`
*/
/**
* When above line is executed, `fetch` makes API call and return a `promise` instantly which is in `Pending` state and Javascript doesn't wait to get it `fulfilled`
* And in next line it console out the `pending promise`.
* NOTE: chrome browser has some in-consistency, the moment console happens it shows in pending state but if you will expand that it will show fulfilled because chrome updated the log when promise get fulfilled.
* Once fulfilled data is there in promiseResult and it is inside body in ReadableStream format and there is a way to extract data.
*/

Now we can attach callback to above response?

Using .then

const URL = "https://api.github.com/users/alok722";
const user = fetch(URL);
user.then(function (data) {
console.log(data);
});
// And this is how Promise is used.
// It guarantees that it could be resolved only once, either it could be `success` or `failure`
/**
A Promise is in one of these states:
pending: initial state, neither fulfilled nor rejected.
fulfilled: meaning that the operation was completed successfully.
rejected: meaning that the operation failed.
*/

💡Promise Object are immutable.
-> Once promise is fulfilled and we have data we can pass here and there and we don’t have to worry that someone can mutate that data. So over above we can’t directly mutate user promise object, we will have to use .then

💡What is Promise?
-> Promise object is a placeholder for certain period of time until we receive value from asynchronous operation.

-> A container for a future value.

-> A Promise is an object representing the eventual completion or failure of an asynchronous operation.

We are now done solving one issue of callback i.e. Inversion of Control

But there is one more issue, callback hell…

// Callback Hell Example
createOrder(cart, function (orderId) {
proceedToPayment(orderId, function (paymentInf) {
showOrderSummary(paymentInf, function (balance) {
updateWalletBalance(balance);
});
});
});
// And now above code is expanding horizontally and this is called pyramid of doom.
// Callback hell is ugly and hard to maintain.
// 💡 Promise fixes this issue too using `Promise Chaining`
// Example Below is a Promise Chaining
createOrder(cart)
.then(function (orderId) {
proceedToPayment(orderId);
})
.then(function (paymentInf) {
showOrderSummary(paymentInf);
})
.then(function (balance) {
updateWalletBalance(balance);
});
// ⚠️ Common PitFall
// We forget to return promise in Promise Chaining
// The idea is promise/data returned from one .then become data for next .then
// So,
createOrder(cart)
.then(function (orderId) {
return proceedToPayment(orderId);
})
.then(function (paymentInf) {
return showOrderSummary(paymentInf);
})
.then(function (balance) {
return updateWalletBalance(balance);
});
// To improve readability you can use arrow function instead of regular function

Watch Live On Youtube below:

promise in Javascript Youtube Link



Episode 22 (Season 2 : Episode 3) : Creating a Promise, Chaining & Error Handling

Section titled “Episode 22 (Season 2 : Episode 3) : Creating a Promise, Chaining & Error Handling”

const cart = ["shoes", "pants", "kurta"];
// Consumer part of promise
const promise = createOrder(cart); // orderId
// Our expectation is above function is going to return me a promise.
promise.then(function (orderId) {
proceedToPayment(orderId);
});
// Above snippet we have observed in our previous lecture itself.
// Now we will see, how createOrder is implemented so that it is returning a promise
// In short we will see, "How we can create Promise" and then return it.
// Producer part of Promise
function createOrder(cart) {
// JS provides a Promise constructor through which we can create promise
// It accepts a callback function with two parameter `resolve` & `reject`
const promise = new Promise(function (resolve, reject) {
// What is this `resolve` and `reject`?
// These are function which are passed by javascript to us in order to handle success and failure of function call.
// Now we will write logic to `createOrder`
/** Mock logic steps
* 1. validateCart
* 2. Insert in DB and get an orderId
*/
// We are assuming in real world scenario, validateCart would be defined
if (!validateCart(cart)) {
// If cart not valid, reject the promise
const err = new Error("Cart is not Valid");
reject(err);
}
const orderId = "12345"; // We got this id by calling to db (Assumption)
if (orderId) {
// Success scenario
resolve(orderId);
}
});
return promise;
}

Over above, if your validateCart is returning true, so the above promise will be resolved (success),

const cart = ["shoes", "pants", "kurta"];
const promise = createOrder(cart); // orderId
// ❓ What will be printed in below line?
// It prints Promise {<pending>}, but why?
// Because above createOrder is going to take sometime to get resolved, so pending state. But once the promise is resolved, `.then` would be executed for callback.
console.log(promise);
promise.then(function (orderId) {
proceedToPayment(orderId);
});
function createOrder(cart) {
const promise = new Promise(function (resolve, reject) {
if (!validateCart(cart)) {
const err = new Error("Cart is not Valid");
reject(err);
}
const orderId = "12345";
if (orderId) {
resolve(orderId);
}
});
return promise;
}

Now let’s see if there was some error and we are rejecting the promise, how we could catch that?
-> Using .catch

const cart = ["shoes", "pants", "kurta"];
const promise = createOrder(cart); // orderId
// Here we are consuming Promise and will try to catch promise error
promise
.then(function (orderId) {
// ✅ success aka resolved promise handling
proceedToPayment(orderId);
})
.catch(function (err) {
// ⚠️ failure aka reject handling
console.log(err);
});
// Here we are creating Promise
function createOrder(cart) {
const promise = new Promise(function (resolve, reject) {
// Assume below `validateCart` return false then the promise will be rejected
// And then our browser is going to throw the error.
if (!validateCart(cart)) {
const err = new Error("Cart is not Valid");
reject(err);
}
const orderId = "12345";
if (orderId) {
resolve(orderId);
}
});
return promise;
}

Now, Let’s understand the concept of Promise Chaining
-> for this we will assume after createOrder we have to invoke proceedToPayment
-> In promise chaining, whatever is returned from first .then become data for next .then and so on…
-> At any point of promise chaining, if promise is rejected, the execution will fallback to .catch and others promise won’t run.

const cart = ["shoes", "pants", "kurta"];
createOrder(cart)
.then(function (orderId) {
// ✅ success aka resolved promise handling
proceedToPayment(orderId);
return orderId;
})
.then(function (orderId) {
// Promise chaining
// 💡 we will make sure that `proceedToPayment` returns a promise too
return proceedToPayment(orderId);
})
.then(function (paymentInfo) {
// from above, `proceedToPayment` is returning a promise so we can consume using `.then`
console.log(paymentInfo);
})
.catch(function (err) {
// ⚠️ failure aka reject handling
console.log(err);
});
// Here we are creating Promise
function createOrder(cart) {
const promise = new Promise(function (resolve, reject) {
// Assume below `validateCart` return false then the promise will be rejected
// And then our browser is going to throw the error.
if (!validateCart(cart)) {
const err = new Error("Cart is not Valid");
reject(err);
}
const orderId = "12345";
if (orderId) {
resolve(orderId);
}
});
return promise;
}
function proceedToPayment(cart) {
return new Promise(function (resolve, reject) {
// For time being, we are simply `resolving` promise
resolve("Payment Successful");
});
}

Q: What if we want to continue execution even if any of my promise is failing, how to achieve this?
-> By placing the .catch block at some level after which we are not concerned with failure.
-> There could be multiple .catch too. Eg:

createOrder(cart)
.then(function (orderId) {
// ✅ success aka resolved promise handling
proceedToPayment(orderId);
return orderId;
})
.catch(function (err) {
// ⚠️ Whatever fails below it, catch wont care
// this block is responsible for code block above it.
console.log(err);
});
.then(function (orderId) {
// Promise chaining
// 💡 we will make sure that `proceedToPayment` returns a promise too
return proceedToPayment(orderId);
})
.then(function (paymentInfo) {
// from above, `proceedToPayment` is returning a promise so we can consume using `.then`
console.log(paymentInfo);
})

Watch Live On Youtube below:

promise in Javascript Youtube Link

To Be Continued…