Manipulate JavaScript Arrays the Functional Way

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Functional programming is a programming paradigm which states that we create computations as the evaluation of functions and avoid changing state and mutable data.

To write programs in a functional way, we use pure functions and immutable data structures.

In JavaScript, we can easily apply functional principles to arrays by using its built-in array methods.

In this article, we’ll look at the array methods that let us manipulate them in a functional way.

Filtering Items

We can use the filter method to return an array with entries from the original array that has the condition that the callback of the filter method returns.

For example, if we have the following array:

const store = [{  
    name: "Apple",  
    price: 1  
  },  
  {  
    name: "Banana",  
    price: 2  
  },  
  {  
    name: "Grape",  
    price: 1.2  
  }  
];
Enter fullscreen mode Exit fullscreen mode

We can get the items that have price less than 2 as follows:

const cheapItems = store.filter(s => s.price < 2);
Enter fullscreen mode Exit fullscreen mode

Then we get the following for cheapItems:

[  
  {  
    "name": "Apple",  
    "price": 1  
  },  
  {  
    "name": "Grape",  
    "price": 1.2  
  }  
]
Enter fullscreen mode Exit fullscreen mode

Using the filter method fits with the functional paradigm since the function is pure, given the same array and same condition, we always get the same results returned.

It also doesn’t change the existing elements of the array that it’s called on, which means we can’t accidentally change anything from the original array.

Mapping Array Objects

map is used to map entries of an array into something else. It’s frequently used to convert and transform data. Using map fits with the functional programming paradigm because again it’s a pure function that gives the same outputs for the given inputs, and it doesn’t change the original array.

As long as the function we pass into the map function to combine the values is pure, the map method should also be pure since it just calls this callback function and returns the updated values into a new array.

For example, given the following array:

const volumesInLiters = [{  
    name: "Milk",  
    volumeInLiters: 1  
  },  
  {  
    name: "Apple Juice",  
    volumeInLiters: 2  
  },  
  {  
    name: "Orange Joice",  
    volumeInLiters: 1.2  
  }  
];
Enter fullscreen mode Exit fullscreen mode

We can add the volumeInQuarts field to each entry of the object and set the volume in quarts to as the value of each by writing:

const volumesInQuarts = volumesInLiters.map(v => {  
  v = {  
    ...v,  
    volumeInQuarts: v.volumeInLiters * 1.057  
  };  
  return v;  
})
Enter fullscreen mode Exit fullscreen mode

We convert v.volumeInLiters * 1.057 and set it to volumeInQuarts for each entry.

Then we get:

[  
  {  
    "name": "Milk",  
    "volumeInLiters": 1,  
    "volumeInQuarts": 1.057  
  },  
  {  
    "name": "Apple Juice",  
    "volumeInLiters": 2,  
    "volumeInQuarts": 2.114  
  },  
  {  
    "name": "Orange Joice",  
    "volumeInLiters": 1.2,  
    "volumeInQuarts": 1.2684  
  }  
]
Enter fullscreen mode Exit fullscreen mode

Using Reduce to Combine Values of Array Entries

Like filter and map, reduce also fits with the functional paradigm since we use it to gather entries of an array and return one value by the way that we specify.

As long as the function we pass into the reduce function to combine the values is pure, the reduce method should be pure. The function just calls the callback function we pass into reduce to compute the combined value.

For example, given the following array:

const store = [{  
    name: "Apple",  
    price: 1  
  },  
  {  
    name: "Banana",  
    price: 2  
  },  
  {  
    name: "Grape",  
    price: 1.2  
  }  
];
Enter fullscreen mode Exit fullscreen mode

We can write the following to get the total price of all items:

const totalPrice = store.map(s => s.price).reduce((subtotal, b) => subtotal + b, 0);
Enter fullscreen mode Exit fullscreen mode

We have to use map to map all the entries in the store array to price numbers. Then we can use the reduce method to add the new value to subtotal.

Then we should get 4.2 for totalPrice, which is the total of all the prices of the 3 items in store.

The second argument of reduce is the starting value of the reduction, or combining the values into one.

Conclusion

The filter, map, and reduce array methods are the main methods for manipulating arrays in a functional manner. They all return values and don’t change the array that it’s called on. This makes it difficult to unintentionally change the values.

filter returns an array that meets the condition that we return in the callback that we pass in.

map returns a new array that has the values of the original array mapped to new values in a way that we specify.

reduce combines the values of array entries into one by taking a callback function that we pass in to do the combining and returns the combined value.

The functions are pure if we pass in pure functions to them as callbacks since they just call the functions that we pass in to do the manipulation.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .