Skip to content
Module 05 of 1250 min readBeginner

Functions, control flow, and the apply family

Function definition, if/else, for loops vs apply / sapply / map. When to vectorise.

42%

Listen along

Read “Functions, control flow, and the apply family” aloud

Plays in your browser using on-device text-to-speech — nothing leaves the page.

Learning objectives

By the end of this module, you should be able to:

  • 01Write if/else and the vectorised ifelse() correctly — knowing when each is right
  • 02Define functions with positional and default arguments
  • 03Use the apply family (sapply, lapply, mapply) or purrr's map functions instead of explicit loops
  • 04Recognise when an explicit for loop is genuinely needed

R has the standard if/else and for/while constructs. But idiomatic R prefers vectorised operations and the apply family — explicit loops are usually a sign you're thinking in the wrong language.

if / else

r
rate <- 0.115
if (rate > 0.13) {
stance <- "tight"
} else if (rate > 0.10) {
stance <- "neutral"
} else {
stance <- "loose"
}
# Vectorised: ifelse
rates <- c(0.08, 0.115, 0.14)
stance <- ifelse(rates > 0.10, "tight", "loose")
# c("loose", "tight", "tight")

for loop — usually unnecessary

r
for (i in 1:5) {
print(i)
}
# But you almost never need this in R
rates <- c(0.07, 0.10, 0.12)
# Loop version (don't do this)
total <- 0
for (r in rates) {
total <- total + r
}
# R way: vectorised
sum(rates)

Functions

r
compound <- function(principal, rate, years = 10) {
principal * (1 + rate) ^ years
}
compound(1000, 0.10, 5) # positional
compound(1000, rate = 0.10) # default years = 10

The apply family

Instead of writing loops, R has a family of higher-order functions: sapply, lapply, mapply, apply. They take a function and apply it across a vector, list, or matrix. purrr (tidyverse) provides map, map_dbl, map_chr — same idea, more consistent.

r
rates <- list(c(0.07, 0.10, 0.12), c(0.08, 0.11), c(0.09))
sapply(rates, mean) # 0.0967 0.0950 0.0900 — applies mean to each list element
# purrr version
library(purrr)
map_dbl(rates, mean)

When to vectorise

If you're writing a for loop in R that just builds a vector, you're probably doing it wrong. Either the operation is already vectorised (use it directly), or use sapply/map_dbl. Loops are reserved for genuinely sequential operations.

Exercise

Use sapply() to compute the length of each element in a list of c(c(1,2,3), c(4,5), c(6)).

Key takeaways

  • if() takes one logical; ifelse() vectorises over a logical vector — different tools
  • Explicit for loops are usually a sign you're thinking in the wrong language; reach for sapply/map_dbl first
  • purrr::map_dbl(x, mean) is the cleaner, type-safe successor to sapply(x, mean)
  • Loops are reserved for genuinely sequential operations (Markov chains, recursive simulations)
Loading progress…
LeadAfrikPublic Economics Hub