Understanding Array High Order Methods

Understanding Array High Order Methods

Practical ways to implement map(), reduce() & filter()

When working with arrays, it is very handy to be able to iterate through each item to find one or more elements that we might need or to manipulate an array based on which data items meet a certain set of criteria. JavaScript offers several built-in methods that each iterate over arrays in slightly different ways to achieve different results (such as filter(), forEach(), map(), etc.),

However, the technique which is most flexible and offers us the greatest amount of control is a simple for loop.

function greaterThanTen(arr) {
  let newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > 10) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}

greaterThanTen([2, 12, 8, 14, 80, 0, 1]);

Using a for loop, this function iterates through and accesses each element of the array, and subjects it to an operation that we have created. In this way, we have easily and programmatically determined which data items are greater than 10 and returned a new array

// returned a new array

[12, 14, 80]

but with the array method filter() you can do the same thing in a few lines, which we'll understand and implement in this tutorial ahead. But, first, let's get started with map!!

Understanding map()

First, the map method is yet another method that we can use to loop over arrays. So, the map is actually similar to the for loop method that we studied before but with the difference that the map creates a brand new array based on the original array.

Just like here, Steven (like original array) changes his place with Marc(new array), which transformed into MoonKnight(new array with operation), and just like the original array Steven is safe in mirror world without any change, map() works in the same way

moon.gif So essentially the map method takes an array, loops over that array and in each alteration, it applies a callback function that we specify on our code to the current array element. Let’s take a look at an example.

Suppose that you have an array of numbers where each element represents the radius of a circle as follows:

let circles = [
    10, 30, 50
];

The following illustrates how to calculate the area of each circle and push the result into a new array

let areas = []; // to store areas of circles
let area = 0;
for (let i = 0; i < circles.length; i++) {
    area = Math.floor(Math.PI * circles[i] * circles[i]);
    areas.push(area);
}
console.log(areas);

output

[314, 2827, 7853]

It takes a quite amount of code to accomplish this.

the map() method that allows you to transform the array elements in a cleaner way.

let areas = circles.map(function(radius){
    return Math.floor(Math.PI * radius * radius);
});
console.log(areas);

or


// with arrow function

let areas = circles.map(radius => Math.floor(Math.PI * radius * radius));
console.log(areas);

output

[314, 2827, 7853]

So in this example, we say that each element shall be multiplied by the Pie value and its own square value And with this callback in place, the map method multiplies every single element and puts it into a new array. We say that it maps the values of the original array to a new array and that's why this method is called map.

How it works

  • First, define a function that calculates the area of a circle

  • Then, pass the circleArea function to the map() method. The map() method will call the circleArea function on each element of the circle's array and return a new array with the elements that have been transformed.

Note - the map() method does not change the original array, it creates a new array of all elements that have been transformed by the callback function.

Understanding filter()

Anyway, next up we have the filter method, which as the name says, is used to filter for elements in the original array that satisfy a certain condition.

Meme Context- Move forward, whoever gonna pay the overdue 6-month rent, Surprisingly Manav filtered out by his friends dhamaal-paise.gif

So in the next example, we are only looking for YouTubers with subscribers greater than 3M(three million). So all the elements that pass the test that we specified will make it into a new filtered array. Or in other words, elements for which the condition is true will be included in a new array that the filter method returns. All other elements will get filtered out so they will not be included in the new array

Here you have an array of Youtubers objects where each object contains two properties: name and subscribers

let youtubers = [
    {name: 'PewDiePie', subscribers: 11379262},
    {name: 'Mr Beast', subscribers: 102817513},
    {name: 'Saiman Says', subscribers: 169559},
    {name: 'Dude Perfect', subscribers: 2099451},
    {name: 'Puneet superstar', subscribers: 15260}
];

To find the YouTuber whose subscribers are greater than 3 million, you typically loop over the array elements using a for loop and test if the value of the subscribers property satisfies the condition, like this:

let bigYoutubers = [];
for (let i = 0; i < youtubers.length; i++) {
    if (youtubers[i].subscribers > 3000000) {
        bigYoutubers.push(youtubers[i]);
    }
}
console.log(bigYoutubers);

output

[
    {name: 'PewDiePie', subscribers: 11379262},
    {name: 'Mr Beast', subscribers: 102817513},
]

JavaScript Array provides the filter() method that allows you to do this task in a shorter and cleaner way.

let bigYoutubers = youtubers.filter(function (e) {
    return e.subscribers > 3000000;
});
console.log(bigYoutubers);

or

// with arrow function
let bigYoutubers = youtubers.filter(youtuber => youtuber.subscribers > 3000000);

console.log(bigYoutubers);

// output
[
    {name: 'PewDiePie', subscribers: 11379262},
    {name: 'Mr Beast', subscribers: 102817513},
]

In this example, we call the filter() method of the YouTubers array object and pass a function that tests each element.

Inside the function, we check if the population of each YouTuber in the array is greater than 3 million. If it is the case, the function returns true or false otherwise.

The filter() method includes the only elements in the result array if they satisfy the test in the callback function.

Understanding reduce()

Imagine, if we take every single alien from the Ben10 omnitrix(10 array elements) and mix them with each other and we get result like Kevin11(Single value), I know it's pretty awkward and confusing, but that's how reduce work gifbhay.gif

The reduce method is basically used to boil down all the elements of the original array into one single value. And an example of this can be adding all the elements of an array together. you can imagine this as a snowball, it keeps getting bigger and bigger as it rolls down a hill. And so this is known as the snowball effect and reduce is pretty similar to that or if you are a Madara Uchiha fan, then our mission is to grab all the tailed beasts (total 9) and Revive ten tails!! lol okay? So keep that in mind as a nice analogy.

But we can also do many other interesting things. So for the example of adding up all numbers in the array, we need to specify an operation like this:

arr.reduce(callback( accumulator, currentValue, [, index[, array]] )[, initialValue])

Reducer is a function that takes the accumulator (which is a temporary result) and currentValue from iteration, It performs the operation we want, and then returned value becomes the new accumulator.

Additionally, we can also get an index of the current element and source array, but these two aren’t used often.

we can define our initial accumulator value under initialValue. If we don’t provide it, the first value from an array will become an initial value.

Suppose that you have an array of numbers, like this:

let numbers = [1, 2, 3];

and you want to calculate the total of elements of the array.

Typically, you use a for loop to iterate over the elements and add them up as shown in the following example:

let numbers = [1, 2, 3];  // First, declare an array of three numbers

let sum = 0;  // 
for (let i = 0; i < numbers.length; i++) {
    sum += numbers[i];
}

console.log(sum);

Output:

6

What we have done was to reduce an array into a value.

The Array.prototype allows you to reduce an array to a single value using the reduce() method like this:

let sum = numbers.reduce((acc, val) => acc + val);

or 

// For better understanding
let sum = array.reduce((previousValue, currentValue) => previousValue + currentValue);

Then as the reduce method loops over the array, it keeps adding the currentValue onto the previousValue until at the end of the loop we have the total sum of all the elements.

let numbers = [1, 2, 3];
let sum = numbers.reduce(function (previousValue, currentValue) {
    return previousValue + currentValue;
});

console.log(sum);


output
6

Now it's this value that then actually gets returned from the reduce method in the end. So there is no new array in this case but only the reduced value.

Let's build a simple project and apply everything!

Topic- We gonna build a Wealth app in which we will manipulate random users' ranking, wealth, and status based on their NetWorth!!

Reference- 20 Web Projects With Vanilla JavaScript

Step 1 - Clone the whole HTML & CSS in your code editor, Our focus will be only on JavaScript

Step 2 - Create a new file named script.js

  • First of all, select all the DOM elements that we need.
const main = document.getElementById('main');
const addUserBtn = document.getElementById('add-user');
const doubleBtn = document.getElementById('double');
const showMillionairesBtn = document.getElementById('show-millionaires');
const calculateWealthBtn = document.getElementById('calculate-wealth');

OK, so after selecting everything, let's move on to the next step.

  • Let's initialize an empty array named data here.
let data = [];
  • Here we going to call data and that's basically where we put all of the people after fetch.

  • We are going to use a random user API - (randomuser.me/api)

  • It's going to be an array of objects with names for the first and last name and then a money value, which will be the wealth that we'll actually manipulate

Step 3 - Here we gonna build the logic to fetch users from API

// fetch random users and add money

// fetch three random user
// for adding the first three initial users

getRandomUser();
getRandomUser();
getRandomUser();

async function getRandomUser() {
  const res = await fetch('https://randomuser.me/api');
  const data = await res.json();

  const user = data.results[0];

  const newUser = {
      name: `${user.name.first} ${user.name.last}`,
      money: Math.floor(Math.random() * 1000000)
  };  // localStorage for adding new users

  addData(newUser);
}

Step 4 - Here we gonna add a new object to our data Array and Update the UI

function addData(obj) {
    data.push(obj);

    updateDOM();
    // here () we are not actually passing anything
    // because, we want the default value here of the default data array
}

// Update DOM

function updateDOM(providedData = data) {

    // so to set the default value in function
    // we simply set = data i.e provideData = data


    // Clear main div
    main.innerHTML = '<h2><strong>Person</strong> Wealth</h2>';

providedData.forEach(item => {
    const element = document.createElement('div');
    element.classList.add('person');
    element.innerHTML = `<strong>${item.name}<strong> ${
        formatMoney(item.money)}`;

   main.appendChild(element); 
 });

}

Step 5 - Writing Money format function

basically this convert your numbers from 250000 to > $250,000

// money format
function formatMoney(number) {
 return '$' + number.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
}

Step 6 - Event listeners for the AddUser button

// Event listeners

addUserBtn.addEventListener('click', getRandomUser);

Click Add User🤴 button

let's apply map() method for Doubling wealth

// Double everyone's money

function doubleMoney() {
    data = data.map(user => {
        return { ...user, money: user.money * 2 };
    });

    updateDOM();
}

// Event listeners
doubleBtn.addEventListener('click', doubleMoney);

Click Double Money 💰 button

let's apply filter() method to Show millionaire

// Filter only millionaires

function showMillionaires(){
    data = data.filter(user => user.money > 1000000);
    updateDOM();
}

// Event listeners
showMillionairesBtn.addEventListener('click', showMillionaires);

Click Show Only Millionaires 💵 button

let's apply reduce() method to Calculate Total Wealth

// Calculate the total wealth

function calculateWealth(){
    const wealth = data.reduce((acc, user) =>(acc += user.money), 0);

    const wealthEl = document.createElement('div');
    wealthEl.innerHTML = `<h3>Total Wealth: <strong>${formatMoney(wealth)}</strong></h3>`;
    main.appendChild(wealthEl);
}

// Event listeners
calculateWealthBtn.addEventListener('click', calculateWealth);

Click Calculate entire Wealth 🧮 button