mapply()
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) mapply() applies a function to multiple arguments simultaneously, processing the first element of each argument together, then the second elements, and so on. It is the multivariate counterpart of sapply() — where lapply() loops over a single structure and sapply() loops and simplifies, mapply() handles parallel iteration across multiple inputs.
The function recycles shorter arguments to match the length of the longest, making it useful for operations that need to combine corresponding elements from different vectors or lists.
Syntax
mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FUN | function | — | Function to apply, resolved via match.fun() |
... | vectors or lists | — | Arguments to iterate over in parallel; recycled to the longest length |
MoreArgs | list | NULL | Additional arguments passed to FUN on every call |
SIMPLIFY | logical or character | TRUE | Attempt to reduce the result to a vector, matrix, or higher-dimensional array |
USE.NAMES | logical | TRUE | Use the names of the first ... argument as result names |
Return Value
When SIMPLIFY = FALSE, mapply() always returns a list with one element per iteration. When SIMPLIFY = TRUE (the default), it attempts to simplify the result:
- If all results are scalar numbers, returns a numeric vector
- If all results have the same length, returns a matrix or array
- Otherwise, returns a list
Examples
Repeating values with parallel arguments
The classic example is using mapply() with rep(), where the first argument provides values and the second provides repetition counts:
mapply(rep, 1:4, 4:1)
# [[1]]
# [1] 1 1 1 1
#
# [[2]]
# [1] 2 2 2
#
# [[3]]
# [1] 3 3
#
# [[4]]
# [1] 4
This is equivalent to calling rep(1, times = 4), rep(2, times = 3), rep(3, times = 2), and rep(4, times = 1) in sequence — but done in one call.
Named arguments passed to FUN
When you name the arguments in ..., those names become argument names in the function call. This can make code more readable:
mapply(rep, times = 1:4, x = 4:1)
# Same result as above, but rep() receives named arguments
Fixed additional arguments with MoreArgs
Use MoreArgs to pass constants that don’t change across iterations:
multiply <- function(x, y, factor) x * y * factor
mapply(multiply, c(2, 3, 4), c(10, 20, 30), MoreArgs = list(factor = 0.5))
# [1] 10 30 60
Every call to multiply() receives factor = 0.5 in addition to the values from the vectors.
Anonymous functions for custom operations
For operations that don’t have a ready-made function, pass an anonymous function:
mapply(function(x, y) seq_len(x) + y, c(a = 1, b = 2, c = 3), c(A = 10, B = 0, C = -10))
# $a
# [1] 11
#
# $b
# [1] 2 3
#
# $c
# [1] -9 -8 -7 -6 -5 -4
The names from the first vector (a, b, c) become the names of the result list elements. The anonymous function receives x from the first vector and y from the second, running parallel iteration across both.
Avoiding simplification
When SIMPLIFY = FALSE, the result is always a list regardless of what FUN returns:
result <- mapply(function(x, y) x^y, c(2, 3), c(4, 5), SIMPLIFY = FALSE)
print(result)
# [[1]]
# [1] 16
#
# [[2]]
# [1] 243
This is useful when your function might return vectors of varying lengths, where automatic simplification would fail or produce unexpected array shapes.
Creating a data frame from parallel vectors
You can use mapply() to construct a data frame row-by-row:
names <- c("Alice", "Bob", "Carol")
ages <- c(32, 45, 28)
scores <- c(85.5, 92.0, 78.3)
mapply(function(n, a, s) data.frame(name = n, age = a, score = s),
names, ages, scores, SIMPLIFY = FALSE)
# [[1]]
# name age score
# 1 Alice 32 85.5
# ...
Common Patterns
Using mapply() instead of a for loop: When you find yourself writing a for loop to combine multiple vectors element-by-element, mapply() often provides a cleaner alternative.
# Instead of this:
x <- c(1, 2, 3)
y <- c(10, 20, 30)
result <- numeric(length(x))
for (i in seq_along(x)) {
result[i] <- x[i] + y[i]
}
# Do this:
result <- mapply(function(x, y) x + y, x, y)
Controlling output with SIMPLIFY: The SIMPLIFY argument mirrors the behavior of sapply(). Use SIMPLIFY = FALSE when you need predictable list output and SIMPLIFY = TRUE (the default) when you know your function always returns scalars of the same type.
Gotchas
Recycling with mismatched lengths: If argument lengths aren’t multiples of each other, R recycles the shorter one and emits a warning:
mapply(paste, c("a", "b", "c"), c(1, 2), USE.NAMES = FALSE)
# Warning message:
# longer object length is not a multiple of shorter object length
Empty arguments: If any ... argument has length zero, mapply() returns a list of length zero:
mapply(rep, 1:3, integer())
# list()
Confusion with Hmisc::mApply: The Hmisc package exports a function also called mApply() that operates on matrix margins. If you load both packages, the base version takes precedence, but this can cause confusion in code that expects the Hmisc behavior.
See Also
- sapply() — univariate version with optional simplification
- lapply() — iterate over a single list or vector
- apply() — apply a function over margins of an array or matrix
- Map — identical to
mapply()withSIMPLIFY = FALSE - purrr::pmap — tidyverse equivalent for any number of arguments