# Understanding Array High Order Methods

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1660561752287/4UKsDNpEZ.gif align="left")
 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1660392943774/rkXbSqZh1.gif align="left")

 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1660560458282/hrDatEDtT.gif align="left")

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](https://www.udemy.com/course/web-projects-with-vanilla-javascript/)


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

%[https://codepen.io/manuraj1107/pen/oNqyROo]



#### 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 - (https://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

%[https://codepen.io/manuraj1107/pen/MWVPZVm]



### 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

%[https://codepen.io/manuraj1107/pen/QWmZzmE]

### 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

%[https://codepen.io/manuraj1107/pen/NWYOeYx]



### 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

%[https://codepen.io/manuraj1107/pen/gOeBZvV]


