DEV Community

Cover image for Save time by using array functions in Javascript
Patrick Zocli
Patrick Zocli

Posted on

Save time by using array functions in Javascript

Array transformation functions are valuable tools for Javascript developers. They allow us to easily manipulate the elements of an array and transform them according to our needs. In this article, we will explore three of these functions: map, filter and reduce, talk about a juicy javascript skill called piping and finally talk about when to use these functions or not for optimal performance.

The functions

Map

The map() function allows to transform each element of an array into another one by executing a function on each element. This function is passed as a parameter and takes as arguments three parameters, the last two of which are optional: the current value, the current index and the original array.

Here is how to use map() :

const result = array.map(function(currentValue, currentIndex, array) {
    // code to execute on each element 
});
Enter fullscreen mode Exit fullscreen mode

Let's say we have an array of characters with their life level and attack power :

const characters = [        
    { name: "Mario", life: 100, attack: 50 },
    { name: "Luigi", life: 90, attack: 60 },        
    { name: "Peach", life: 80, attack: 70 },    
    { name: "Toad", life: 70, attack: 80 },     
    { name: "Bowser", life: 60, attack: 90 }  
];
Enter fullscreen mode Exit fullscreen mode

We want to display a list of characters with their life/attack ratio (i.e. their life divided by their attack). We can use map() to transform the array of characters into an array of ratios:

// Define the transformation function that calculates the life/attack ratio for each character  
const ratioLifeAttack = character => character.life / character.attack;   

// Use the map() method on the characters array by passing it the transformation function 
const ratios = characters.map(ratioLifeAttack);

console.log(ratios); 
// display [2, 1.5, 1.1428571428571428, 0.875, 0.6666666666666666]
Enter fullscreen mode Exit fullscreen mode

The map() function traverses each character in the characters array and calculates its life/attack ratio using the life/attack ratio() transformation function. The result is a new ratios array containing the ratios for each character. Here we don't need the other arguments, i.e. the current index and the array being analyzed.

Filter

The filter() function allows to select the elements of an array that satisfy a given condition. It goes through each element of the array and performs a function on each of them. If the function returns true for an element, then filter() adds it to its new array. Otherwise, the element is ignored.

It is used in the following way:

const result = array.filter(function(currentValue, currentIndex, array) { 
    // code to execute on each element 
});
Enter fullscreen mode Exit fullscreen mode

Let's go back to our character example. This time we want to get a list of characters that have a life/attack ratio greater than 1. We can use filter() to select these characters :

// Define the filter function that checks if the life/attack ratio is greater than 1 
const ratioSuperiorAUn = character => character.life / character.attack > 1; 

// Use the filter() method on the characters array by passing it the filter function 
const charactersFilters = characters.filter(ratioSuperiorAny);

console.log(charactersFilters); 
// display [{ name: "Mario", life: 100, attack: 50 }, { name: "Peach", life: 80, attack: 70 }]
Enter fullscreen mode Exit fullscreen mode

Our function goes through each character in the characters array and checks if their life/attack ratio is greater than 1 using the ratioSuperiorAUn() filter function. In case the function returns false, the element is ignored and in case it is not, the element is added to the new array. The result is a new array charactersFilters containing the characters that have a life/attack ratio greater than 1.

Reduce

The reduce() function allows to reduce an array to a single value by executing a function on each element. This function is passed as a parameter and takes as arguments four parameters: the accumulator (which is initialized with the initial value or the first value of the array), the current value, the current index and the original array.

It is used as follows:

const resultat = array.reduce(function(accumulator, currentValue, currentIndex, array) { 
    // code to execute on each element 
}, initialvalue);
Enter fullscreen mode Exit fullscreen mode

Let's consider our character example again. Assuming this time that we want to calculate the sum of all the characters' life levels, we can use reduce() in the following way:

// Define the reduce function that calculates the sum of the life levels
const sumLife = (accumulator, character) => accumulator + character.life;

// Use the reduce() method on the characters array by passing it the sumLife function
const lifeTotal = characters.reduce(lifeSum, 0);

console.log(sumLife); 
// display 400
Enter fullscreen mode Exit fullscreen mode

On each element of the array, reduce() executes the reduce function sumLives() which takes as arguments the accumulator (which is initialized with the initial value 0) and the current value (which is the current element of the array).

On the first iteration, the accumulator is 0 and the current value is the first element of the array, which is { name: "Mario", life: 100, attack: 50 }. The reduce function then adds the value of life of the current element to the accumulator and updates its value with the result, giving accumulator = 0 + 100 = 100.

On the second iteration, the accumulator is now 100 and the current value is the second element of the array, which is { name: "Luigi", life: 90, attack: 60 }. The reduce function again adds the value of life of the current element to the accumulator and updates its value with the result, so accumulator = 100 + 90 = 190.

This operation is repeated for each element of the array until all elements have been processed. When all the elements of the array have been processed, the accumulator contains the sum of all the characters' life levels, which is 400 in our example. The final value of the accumulator is then returned by the reduce() function as the final result.

Advanced data processing with the pipe

Among all the features offered by JavaScript, the pipe is probably one of my favorites. This technique of combining array transformation functions allows us to process data in a more complex way and solve complex problems in an efficient way. With the pipe, we can chain multiple transformation functions together in sequence and use the result of each function as input for the next. It's an incredibly powerful and convenient feature that you'll definitely love.

Here is an example of a pipe using the map() and filter() functions:

const characters = [
    { name: "Mario", life: 100, attack: 50 },
    { name: "Luigi", life: 90, attack: 60 },
    { name: "Peach", life: 80, attack: 70 },
    { name: "Toad", life: 70, attack: 80 },
    { name: "Bowser", life: 60, attack: 90 }
];

// The transformation function "ratioLifeAttack" calculates the life/attack ratio for each character
const ratioLifeAttack = character => character.life / character.attack;

// The filter function "filterRatioHigh" keeps only the characters with a life/attack ratio higher than 1
const filterHighRatio = character => ratioLifeAttack(character) > 1;

// We chain the functions "ratioLifeAttack" and "filterRatioHigh" using the pipe
const charactersFilters = characters
    .map(ratioLifeAttack)
    .filter(filterHighRatio);

console.log(charactersFilters); 
// display [{ name: "Mario", life: 100, attack: 50 }, { name: "Peach", life: 80, attack: 70 }]
Enter fullscreen mode Exit fullscreen mode

In this example, we created a transformation function LifeAttackRatio that calculates the life/attack ratio for each character, as well as a filter function HighRatioFilter that keeps only characters with a life/attack ratio greater than 1. Using the pipe, we chained these two functions together so that we first calculated the life/attack ratio for each character, and then kept only characters with a high ratio. The final result is an array containing only Mario and Peach, who have a life/attack ratio higher than 1.

It is also possible to combine the reduce() function with other transformation functions. For example, we can use the pipe to calculate the average of all the characters' life/attack ratios:

const characters = [
    { name: "Mario", life: 100, attack: 50 },
    { name: "Luigi", life: 90, attack: 60 },
    { name: "Peach", life: 80, attack: 70 },
    { name: "Toad", life: 70, attack: 80 },
    { name: "Bowser", life: 60, attack: 90 }
];

// The transformation function "ratioLifeAttack" calculates the life/attack ratio for each character
const ratioLifeAttack = character => character.life / character.attack;

// The reduction function "sumRatios" calculates the sum of all the ratios passed as input
const sumRatios = (sum, ratio) => sum + ratio;

// We chain the functions "ratioLifeAttack", "reduce" and "sumRatios" using the pipe
const averageRatios = characters
    .map(ratioLifeAttack)
    .reduce(sumRatios, 0) / characters.length;

console.log(averageRatios); 
// display 1.1428571428571428
Enter fullscreen mode Exit fullscreen mode

Here, we first transformed each element of the table into its life/attack ratio, then reduced all these ratios into a single value: the sum of all ratios. Finally, we divided this sum by the number of characters to get the average of these ratios.

It is important to note that the pipe is not a native JavaScript function, but rather a programming technique that consists of chaining several functions together in order to process data in a more complex way.

There are various ways to implement a pipe in JavaScript code, but the most common technique is to use the map(), filter() and reduce() function chain.

Let's talk about performance

It is important to consider performance when using these functions. Indeed, although they are very convenient and simplify the code a lot, they can be slightly slower than classical loops combined with if conditions. However, this performance difference is usually negligible for reasonable array sizes. In case you are working with very large arrays, it may be better to use a classic loop to optimize the performance of your code.

It is also important to note that these functions are very efficient in terms of memory, because they do not create new arrays at each iteration as a classical loop would. Instead, they use the same original array and simply change the values of its elements. This reduces memory usage and improves the performance of your code.

Summary

Array transformation functions are powerful and efficient tools for processing data in Javascript. They allow us to easily transform the elements of an array according to our needs, without using loops or complex conditions. We have seen how to use map(), filter() and reduce() to perform operations on array elements, but there are other array transformation functions such as sort(), every(), some(), and other. It is important to choose the function that best suits your needs to avoid overloading your code and improve its performance.


Did you like this article? Share it with your friends and enemies (you never know, maybe they need to make up with you). And if you have any questions or comments, don't hesitate to send them to me. I love to talk tech. And if you run out of ideas you can always leave me a little feedback, we never get enough.

Click here to access the code

Top comments (0)