DEV Community

loading...

Higher Order Array Methods in JavaScript

shrihankp profile image Shrihan Kumar Padhy ・9 min read

Introduction

Higher order functions are functions that operate on other functions, either by receiving them as arguments or by returning them. It is a function that accepts a function as a parameter or returns a function as the output.

In this article, I am going to show you the most commonly used such methods when it comes to arrays.

Array.prototype.map

This is one of the simplest functions you are going to use while working with Arrays. It forms a new array by calling the function passed into it as an argument, on each and every element of the Array. It will map each of the return values of the callback and create a new array.

The callback passed to the map() function can accept any of the three arguments: item, index, array.

Example 1

Given an array of integers, create a new array in which the double of each integer in the first array is stored, and log it to the console.

Solution:

const givenArray = [477, 8914, 40461, 599148];
const newArray = givenArray.map(n => n * 2);
console.log(newArray); // console: [954, 17828, 80922, 1198296]
Enter fullscreen mode Exit fullscreen mode

Example 2

Given an array of singular nouns, create a new array that stores the plural noun of each of the words in the first array, and log it to the console (assume that the singular nouns can be made plural by adding a 's').

Solution:

const givenArray = [ 'pen', 'book', 'code' ];
const newArray = givenArray.map(w => w + 's');
console.log(newArray); // console: ['pens', 'books', 'codes']
Enter fullscreen mode Exit fullscreen mode

Array.prototype.filter

The filter() function is what you'd use if you're creating a search bar from a given list of items, for example. The filter() method also creates a new array by executing the passed callback on every element of the array, and keeps it in the resulting array IF and ONLY IF the element passes the Boolean test returned by the callback.

The callback passed into the filter() method accepts any of the three arguments: item, index and array; same as the map() method.

Example 1

Given an array of costs of different products, create a new array with the costs from the input array if the cost is <= $350, and print it to the console.

Solution:

const givenArray = [390, 190, 311.85, 67, 19048, 5000, 670];
const newArray = givenArray.filter(c => c <= 350);
console.log(newArray) // console: [190, 311.85, 67];
Enter fullscreen mode Exit fullscreen mode

Example 2

Given an array of objects with the city name and population, create an array of integers with objects from the first array if the population of that particular city is >= 5 million.

Solution:

const givenArray = [
  { "name": "Shanghai", "population": 24300000 },
  { "name": "Los Angeles", "population": 3792621 },
  { "name": "New Delhi", "population": 21800000 },
  { "name": "Mumbai", "population": 18400000 },
  { "name": "Chicago", "population": 2695598 },
  { "name": "Houston", "population": 2100263 },
];
const newArray = givenArray.filter( ({ population }) => population >= 5000000);
console.log(newArray); // console: [{name: "Shanghai", population: 24300000}, {name: "New Delhi", population: 21800000}, {name: "Mumbai", population: 18400000}]
Enter fullscreen mode Exit fullscreen mode

Array.prototype.reduce

The reduce() method creates a new array, executing the callback passed into it on every element, and outputs a single value. It does something on every element and keeps a record of the calculations in an accumulator variable and when no more elements are left, it returns the accumulator.

The reduce() function itself takes two inputs: (a) the reducer function or callback; (b) an optional starting point or initialValue.

The reducer function or the callback accepts 4 arguments: accumulator, currentItem, index, array.

If the optional initialValue is given, the accumulator at the first iteration will be equal to the initialValue and the currentItem will be equal to the first element in the array. Otherwise, the accumulator would be equal to the first item in the input array, and the currentItem will be equal to the second item in the array.

Sounds confusing? Let's have a look at two examples:

Example 1

(i) Given an array of numbers, find the sum of every element in the array, and log it to the console.

Solution:

const givenArray = [1, 2, 3, 4, 5];
const sum = givenArray.reduce((acc, curr) => acc + curr);
console.log(sum); // console: 15
Enter fullscreen mode Exit fullscreen mode

Let's have a look at the accumulator and the current value...:

  • at the first iteration: acc=1(givenArray[0]), curr=2(givenArray[1])
  • at the second iteration: acc=3(givenArray[0] + givenArray[1]), curr=3(givenArray[2])
  • at the third iteration: acc=6(givenArray[0] + givenArray[1] + givenArray[2]), curr=4(givenArray[3])
  • at the fourth iteration: acc=10(givenArray[0] + givenArray[1] + givenArray[2] + givenArray[3]), curr=5(givenArray=[4])
  • finally: acc=15 (sum of all elements) (array iteration ended)

You can view this yourself by running a console.log inside the function like so: console.log("iteration: acc="+acc+" curr="+curr);

(ii) Given an array of numbers, find the sum of every element in the array, starting with 8, and log the result to the console

Solution:

const givenArray = [1, 2, 3, 4, 5];
const sum = givenArray.reduce((acc, curr) => acc + curr, 8);
console.log(sum); // console: 23
Enter fullscreen mode Exit fullscreen mode

Note: Here, we are passing the optional initialValue parameter to the reduce() function, saying that we want to start with 8 and do whatever we want inside the callback.
Again, you can test the values of acc and curr and by adding a console.log like above.

Example 2

Given an array of numbers, find the average of them, and log it to the console.

Solution:

const givenArray = [1, 2, 3, 456, 108115, 45909.15154, 1988.1545, 145e8];
const average = (givenArray.reduce((acc, curr) => acc + curr)) / givenArray.length;
console.log(average); // console: 1812519559.288255
Enter fullscreen mode Exit fullscreen mode

If you're confused from the third line, it basically calculates the sum first, and divides the return value by the length of givenArray. You could also use:

const givenArray = [1, 2, 3, 456, 108115, 45909.15154, 1988.1545, 145e8];
const average = givenArray.reduce((acc, curr, index) => ( index == (givenArray.length -1) ) ? (acc + curr) / givenArray.length : acc + curr);
console.log(average); // console: 1812519559.288255
Enter fullscreen mode Exit fullscreen mode

This is a complete no-no for readability and for the KISS principle, but I ain't a cop, use whichever method you like 😉

Array.prototype.forEach

The forEach method is similar to the for(let i = 0; i < array.length, i++){} syntax. It loops through the array and runs the given callback for each of the elements of the array.

The callback function passed to the forEach function can accept the currentItem, index, array.

Example

Given an array of numbers, log every number to the console(wat?!).

Solution:

const arr = [1, 2, 3, 4, 5, 6, 7, 8];
arr.forEach(val => console.log(val));
/* console:
1
2
3
4
5
6
7
8
*/
Enter fullscreen mode Exit fullscreen mode

The big difference between the map and forEach method is that the map method creates a new array, "mapping" the return value of the callback and create a new array, while the forEach method just iterates over the array.

Array.prototype.some and Array.prototype.every

The some method tests whether at least one element of the array complies with the given test in the callback, and returns true or false.

The callback function passed to the some function can accept the currentItem, index, array.

Example 1

Given two arrays of numbers, test whether each of the arrays have at least one number that is > 5, and log the result to the console.

Solution:

const givenArray1 = [1, 2, 3, 5, 8];
const givenArray2 = [1, 2, 3, 4, 5];
const testArray1 = givenArray1.some(n => n > 5);
const testArray2 = givenArray2.some(n => n > 5);
console.log(`givenArray1: ${testArray1}; givenArray2: ${testArray2}`); // console: givenArray1: true; givenArray2: false
Enter fullscreen mode Exit fullscreen mode

The every method is pretty similar to the some method, but it tests whether all the elements of the array complies with the given test in the callback, and returns true or false.

The callback function passed to the every function can accept the currentItem, index, array.

Example 2

Given two arrays of numbers, test whether each of the arrays have all the numbers >= 5, and log the result to the console.

Solution:

const givenArray1 = [10, 9, 8, 7, 6];
const givenArray2 = [5, 1, 2, 785, 45];
const testArray1 = givenArray1.some(n => n > 5);
const testArray2 = givenArray2.some(n => n > 5);
console.log(`givenArray1: ${testArray1}; givenArray2: ${testArray2}`); // console: givenArray1: true; givenArray2: false
Enter fullscreen mode Exit fullscreen mode

Array.prototype.flat and Array.prototype.flatMap

The flat method creates a new Array with all the elements, and if the element is an array, then it "flattens" the element and adds all the sub-array elements to the returned array. By default, it will only flatten the array upto 1 level.

The flat method can accept only one optional argument, the level or depth up till which the array will be "flattened".

Example 1

Given an array of arrays of numbers, find the sum of every number inside the array as well as the sub-arrays, and log the sum to the console.

Solution:

const givenArray = [
  [1, 2, 3, 4, 5, 6],
  [10, 20, 30, 40, 50, 60],
  [100, 200, 300, 400, 500, 600]
];
const sum = 
  givenArray
    .flat() // flattens the array
    .reduce((acc, curr) => acc + curr); // finds the sum
console.log(sum); // console: 2331
Enter fullscreen mode Exit fullscreen mode

The flatMap method is the combination of the flat method and the map method. It first "flattens" the array, runs the callback for each element and "maps" the return value to the corresponding element, and finally returns the "flattened and mapped" array. If you use something like: arr.flatMap(...), its equivalent to arr.flat().map(...). But, there's one catch: you cannot flatten the array by levels more than one, for that you need to use the .flat(...).map(...) syntax.

The flatMap method accepts the same arguments as the map method, and so does the callback.

Example 2

Given an array of arrays of users, create a new array with a single list of all the first names of the users, and log it to the console.

Solution:

const users = [
  [
    { "firstName": "Lorem", "lastName": "Ipsum" },
    { "firstName": "Dolor", "lastName": "Sit" },
    { "firstName": "Amet", "lastName": "Consectetur" }
  ],
  [
    { "firstName": "Adipiscing", "lastName": "Elit" },
    { "firstName": "Etiam", "lastName": "Lobortis" },
    { "firstName": "Lorem", "lastName": "Elit" }
  ],
  [
    { "firstName": "Lorem", "lastName": "Ipsum" },
    { "firstName": "Dolor", "lastName": "Sit" },
    { "firstName": "Amet", "lastName": "Consectetur" }
  ],
  [
    { "firstName": "Adipiscing", "lastName": "Elit" },
    { "firstName": "Etiam", "lastName": "Lobortis" },
    { "firstName": "Lorem", "lastName": "Elit" }
  ]
];

const usersFirstNames = users.flatMap(usersGroup => usersGroup.map(u => u.firstName));

console.log(usersFirstNames); // console: ["Lorem", "Dolor", "Amet", "Adipiscing", "Etiam", "Lorem", "Lorem", "Dolor", "Amet", "Adipiscing", "Etiam", "Lorem"]
Enter fullscreen mode Exit fullscreen mode

Array.prototype.find

The find method returns the first element of the array that satisfies the Boolean test in the callback. If no element passes the Boolean test, undefined is returned.

The callback passed to the find function can accept any of the three arguments: item, index, array.

Example

Given an array of objects with fruits, find the 'apples' and log the corresponding object to the console.

Solution:

const fruits = [
  {"name": "bananas", "quantity": 8},
  {"name": "cherries", "quantity": 3},
  {"name": "apples", "quantity": 80}
];

const apples = fruits.find( ({name}) => name == "apples" );
console.log(apples); // console: {"name": "apples", "quantity": 80}
Enter fullscreen mode Exit fullscreen mode

Array.prototype.sort

The sort method is self-explanatory: it "sorts" an array in place and returns a sorted the array. The default sort order is ascending.

Note the words "in place". It means that the original array is changed and the same reference to the array is returned. So, originalArray===newArray, if nothing is sorted.

It takes a Function that specifies the criteria of sorting.

Example 1

Given an array of numbers, sort the array by ascending order and log the sorted array to the console.

Solution:

const givenArray = [4, 5, 2, 1, 3];
givenArray.sort((a, b) => a - b);
console.log(givenArray);
Enter fullscreen mode Exit fullscreen mode

Example 2

Given an array of contacts, sort them in alphabetical order by name, and log the sorted array.

Solution:

const givenArray = [
  {"name": "Yosha Gamuda", "phone": 1234567890},
  {"name": "Portia Umeng", "phone": 4894759371},
  {"name": "Yosha Gamuda", "phone": 1234567890},
  {"name": "Portia Umeng", "phone": 4894759371}
];
givenArray.sort(({name1}, {name2}) => {
  name1 = name1.toUpperCase();
  name2 = name2.toUpperCase();
  return (name1 < name2) ? -1 : (name1 > name2) ? 1 : 0);
});
console.log(givenArray);
Enter fullscreen mode Exit fullscreen mode

The way sort() works is a bit different than the others. Quoting this MDN doc:

If compareFunction is supplied, all non-undefined array elements are sorted according to the return value of the compare function (all undefined elements are sorted to the end of the array, with no call to compareFunction). If a and b are two elements being compared, then:

  • If compareFunction(a, b) returns less than 0, sort a to an index lower than b (i.e. a comes first).
  • If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAScript standard only started guaranteeing this behavior in 2019, thus, older browsers may not respect this.
  • If compareFunction(a, b) returns greater than 0, sort b to an index lower than a (i.e. b comes first).
  • compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned, then the sort order is undefined.

To compare numbers instead of strings, the compare function can subtract b from a. The following function will sort the array in ascending order (if it doesn't contain Infinity and NaN).

Conclusion

I know this article has ABSOLUTELY LEVIATHAN AMOUNT of information. There are loads of others, but essentially, you need not know every method in Array.prototype to work with arrays. Thank you for reading this article, I hope you enjoyed it. Any feedback will be much, much appreciated: good or bad ;)

Discussion (0)

pic
Editor guide