Using Array Functions and Composition to Talk to JSON Like a Human

function-assembly

In case you haven’t paid much attention to function composition, you should honestly take a second look and reconsider the powerful benefits. Think about it like this, you ask what you want to get, and Javascript decides how to do it. Rather than writing tons of nested loop blocks and statements, just write abstractions that look like verbal sentences. To accomplish this, we’re gonna be using array functions and we’re gonna glue them together to solve problems by describing solutions.

Javascript already provides a good collection of methods to manipulate and query arrays out of the box. I’ll be using some of the most relevant ones, such us map, filter, find, reduce, and some. Check the Mozilla Developer Network for more information about them.

For these examples we’re gonna be targeting the following JSON collection of music records that contain album, artist, rating, genre, and recording information.

Expand complete JSON used in this exercise

Our goals:

  • Get the best (highest rated) records, anything above 4 stars
  • Get the best records by a specific genre
  • Get the artist names of the best records by genre
  • Take the album name from the earliest release
  • Take one artist name that starts with the letter ‘A’, and uppercase it
  • Get a unique (not repeated) list of all the release formats from all the records

Grab the best records

filter() applies the callback function for each element in the array, returning a new array of all the values where the condition was met. So if I applied filter on an array of 5 elements where the condition was only met for 2 elements, then the returned array will have a length of 2.

filter-method

Grab best music by genre

First we need to get the music by genre, for this we need to go through all of the records and see if the specified genre is inside of that genre array property. Then filter all of the records where the genre was found.

some() executes the callback for each element in the array until it finds one where the condition provided returns true. When the first condition is satisfied, then it stops and doesn’t traverse the rest of the array.

some-method

Putting the last 2 functions together:

When you chain individual actions, bigger problems can be solved.

In the last example we used function composition as a way to apply a function to the results of another. This is fundamentally written in the following way:

f(g(x))

Function g is called with a passed value of x, and the result of g is passed to function f. We can already see how wrapping functions on top of each other can scale to having more complex expressions. Let’s add another layer of complexity.

Take the artist names of the best records by genre

map() applies the callback function to each of the items in the array, creating a new array of all new values that resulted by applying the callback function to each one of them.

sort-composition-method

A better composition

The call we just did, pickArtistName(grabBestMusic(grabRock(music))) can definitely be written in a more reusable way that is also easier to read, and solves an important issue, where the executed functions loose track of their context or value of this. This leads us to the following function that will be in charge of chaining these calls in order.

compose would now apply each function from left to right by passing the result from one function to the next one, and so on. This way you can re-arrange, replace, remove or insert actions as you wish, making it now easier to read and maintain.

Now, the previous query would be written as such:

The compose method implementation looks like this:

Grab the album title from the oldest record

One way to do this, would be to first sort all of the records by release year, putting the earliest (oldest) at the beginning. And then just grabbing the album title from that first record.

To make sort work for sub-properties, you need to pass a callback also called the comparator which contains the formula of how you want to sort your items. In this case we need to sort in ascending order.

sort-composition-method

Get an artist name that starts with the letter ‘A’, and uppercase it

Solving these problems should be exactly like giving orders. You could even just start by writing the solution, and then go from there.

find() Iterates the array until the callback function returns true and returns that element. Very similar to findIndex() which instead of returning the actual element, it returns the index.

Get a unique list of all formats

The first thing we need to do to make this happen is to grab all of the genre arrays of all the records. Then we’re gonna concatenate all those arrays to form a single array, and finally we’re gonna remove all the duplicates.

reduce() executes the callback function for each element in the array, then applies a function against an initial accumulator and each value of the array (from left-to-right) to reduce it to a single value.

reduce-method

Finishing up

If you look closely, by chaining methods we treated functions as operators, basically acting between values. This touches on a very important characteristic of functional programming called higher-order functions. Which are basically functions that take other functions as arguments and/or produce another function as its result. See also pure functions.

Hopefully this exercise served as a good start to explore more ways to write more reusable, and readable code. To go deep into this topic I highly recommend reading books about functional programming, including Dan Mantyla’s book and the great Javascript Allonge.