rguides

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

ParameterTypeDefaultDescription
FUNfunctionFunction to apply, resolved via match.fun()
...vectors or listsArguments to iterate over in parallel; recycled to the longest length
MoreArgslistNULLAdditional arguments passed to FUN on every call
SIMPLIFYlogical or characterTRUEAttempt to reduce the result to a vector, matrix, or higher-dimensional array
USE.NAMESlogicalTRUEUse 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() with SIMPLIFY = FALSE
  • purrr::pmap — tidyverse equivalent for any number of arguments