3MW (Using functions instead of for-loops)

Guten Tag!

Many greetings from Ulm, Germany.

Last week, I’ve attended a beginner’s workshop on JavaScript (JS). And one thing that I found striking is that JS uses map functions instead of for loops all the time.

What I found most interesting is that the syntax is extremely similar to R’s functional programming syntax. So today, let me show you how to use functions instead of for-loops in R. And once you understand that, you will have no problem understanding the JS version of that. You know, so that you’re prepared when you decide to go on a JS adventure.

And if you’re a video person, you can also check out my new explainer video on using functions instead of for-loops.

Basic for-loop example

Take a look at the following dataviz.

What you see here is the life expectancy over time for different countries. The lines are just regular trend lines for each continent that you get from a linear regression.

Imagine that you want to compute the slopes of these lines manually (instead of using ggplot()). You could get the job done using a for-loop like so:

This code sets up an empty vector and then fills it by iterating over continents where it

  1. filters the data for each continent

  2. runs a linear regression with the filtered data

  3. extracts the regression’s slope

The most annoying part of this that we have a lot of code for a very simple thing. More importantly, we had to take care of all the bookkeeping (by initializing an empty vector and saving results into it). But there’s a better way.

Nest the data

To use functional programming, we first have to nest our data so that we have a tibble with list-like columns:

This is just a regular tibble where we have a whole data set nested into each cell of the second column. The great thing about this is that we can just pass nested_data to mutate() and compute all the things like we normally would. We just have to understand how to work with these list-like columns.

Enter map()

With map() from {purrr} we can iterate over each cell of a list-like column. Basically, map() is like a for-loop but in a very concise one-line syntax. Take a look at the code and I’ll explain what it does next.

As you can see, map() takes two arguments:

  1. A list (or vector) of things to iterate over

  2. A function that is applied to each element of the list

Notice that we have declared the function for the second step inline by using the function(x) syntax. We could do exactly the same thing but in a shorter way by using R’s \(x) function syntax. That’s what we do in the next step.

Great, we have exactly the same results as before. But now our code is more concise and our results are all collected in a single tibble. Great, isn’t it?

If you want to see more details on how to work with map(), check out my newest video. For now, let me make good on my promise and show you how you can apply this new-found knowledge directly in JS.

Maps in JavaScript

Take a look at this JS array (which I have taken straight from Allison Horst’s excellent JS workshop). It’s written in typical JS format: Each entry is an object with two properties bill and tipPercent.

Code appears below results in ObservableHQ

You could access a specific entry e.g. with restaurantBills[1].bill.

Now, with a map function we could iterate over each object from restaurantBills and calculate the tip. It works exactly the same as in R. The only real difference is that instead of writing function(x) or \(x) as in R, we write x =>.

Alright, that’s a wrap. Hope you’ve enjoyed this week’s newsletter. If you want to reach out to me, just reply to this mail or find me on Twitter.

See you next week!
Albert 👋

Reply

or to participate.