Skip to content
AgileLogics
5 min read

The apply Family

Prerequisites: Functions, Lists

The apply family of base R functions runs a function on each element of a vector, list, or matrix, and collects the results — replacing many for loops.

lapply and sapply

words <- c("apple", "banana", "kiwi")

lapply(words, nchar)
sapply(words, nchar)
sapply(1:3, \(n) n^2)
[[1]]
[1] 5

[[2]]
[1] 6

[[3]]
[1] 4

 apple banana   kiwi
     5      6      4
[1] 1 4 9
  • lapply always returns a list — one element per input.
  • sapply simplifies the result to a vector when it can (and uses the input as names when the input is text).

vapply — safer in functions

sapply can return different types depending on the input, which causes surprises inside functions. vapply states the expected result type:

vapply(c("apple", "kiwi"), nchar, FUN.VALUE = integer(1))
apple  kiwi
    5     4

Applying over data frame columns

A data frame is a list of columns, so sapply works on columns:

df <- data.frame(a = c(1, 2, 3), b = c(10, 20, 30))
sapply(df, mean)
 a  b
 2 20

apply for matrices, and mapply for several inputs

m <- matrix(1:6, nrow = 2)
apply(m, 1, sum)
apply(m, 2, max)

mapply(\(x, y) x * y, 1:3, 4:6)
[1]  9 12
[1] 2 4 6
[1]  4 10 18

apply(m, 1, ...) works row by row; apply(m, 2, ...) column by column.

Don't forget vectorization

Before reaching for sapply(x, \(v) v * 2), check whether a vectorized expression does the job: x * 2. The apply family is for functions that genuinely have to run once per element.