Become an expert in R — Interactive courses, Cheat Sheets, certificates and more!
Get Started for Free

reduce

Reduce a list to a single value by iteratively applying a binary function


Description

reduce() is an operation that combines the elements of a vector into a single value. The combination is driven by .f, a binary function that takes two values and returns a single value: reducing f over 1:3 computes the value f(f(1, 2), 3).

Usage

reduce(.x, .f, ..., .init, .dir = c("forward", "backward"))

reduce2(.x, .y, .f, ..., .init)

Arguments

.x

A list or atomic vector.

.f

For reduce(), and accumulate(), a 2-argument function. The function will be passed the accumulated value as the first argument and the "next" value as the second argument.

For reduce2() and accumulate2(), a 3-argument function. The function will be passed the accumulated value as the first argument, the next value of .x as the second argument, and the next value of .y as the third argument.

The reduction terminates early if .f returns a value wrapped in a done().

...

Additional arguments passed on to the mapped function.

.init

If supplied, will be used as the first value to start the accumulation, rather than using .x[[1]]. This is useful if you want to ensure that reduce returns a correct value when .x is empty. If missing, and .x is empty, will throw an error.

.dir

The direction of reduction as a string, one of "forward" (the default) or "backward". See the section about direction below.

.y

For reduce2() and accumulate2(), an additional argument that is passed to .f. If init is not set, .y should be 1 element shorter than .x.

Direction

When .f is an associative operation like + or c(), the direction of reduction does not matter. For instance, reducing the vector 1:3 with the binary function + computes the sum ((1 + 2) + 3) from the left, and the same sum (1 + (2 + 3)) from the right.

In other cases, the direction has important consequences on the reduced value. For instance, reducing a vector with list() from the left produces a left-leaning nested list (or tree), while reducing list() from the right produces a right-leaning list.

Life cycle

reduce_right() is soft-deprecated as of purrr 0.3.0. Please use the .dir argument of reduce() instead. Note that the algorithm has changed. Whereas reduce_right() computed f(f(3, 2), 1), reduce(.dir = \"backward\") computes f(1, f(2, 3)). This is the standard way of reducing from the right.

To update your code with the same reduction as reduce_right(), simply reverse your vector and use a left reduction:

# Before:
reduce_right(1:3, f)

# After:
reduce(rev(1:3), f)

reduce2_right() is soft-deprecated as of purrr 0.3.0 without replacement. It is not clear what algorithmic properties should a right reduction have in this case. Please reach out if you know about a use case for a right reduction with a ternary function.

See Also

accumulate() for a version that returns all intermediate values of the reduction.

Examples

# Reducing `+` computes the sum of a vector while reducing `*`
# computes the product:
1:3 %>% reduce(`+`)
1:10 %>% reduce(`*`)

# When the operation is associative, the direction of reduction
# does not matter:
reduce(1:4, `+`)
reduce(1:4, `+`, .dir = "backward")

# However with non-associative operations, the reduced value will
# be different as a function of the direction. For instance,
# `list()` will create left-leaning lists when reducing from the
# right, and right-leaning lists otherwise:
str(reduce(1:4, list))
str(reduce(1:4, list, .dir = "backward"))

# reduce2() takes a ternary function and a second vector that is
# one element smaller than the first vector:
paste2 <- function(x, y, sep = ".") paste(x, y, sep = sep)
letters[1:4] %>% reduce(paste2)
letters[1:4] %>% reduce2(c("-", ".", "-"), paste2)

x <- list(c(0, 1), c(2, 3), c(4, 5))
y <- list(c(6, 7), c(8, 9))
reduce2(x, y, paste)


# You can shortcircuit a reduction and terminate it early by
# returning a value wrapped in a done(). In the following example
# we return early if the result-so-far, which is passed on the LHS,
# meets a condition:
paste3 <- function(out, input, sep = ".") {
  if (nchar(out) > 4) {
    return(done(out))
  }
  paste(out, input, sep = sep)
}
letters %>% reduce(paste3)

# Here the early return branch checks the incoming inputs passed on
# the RHS:
paste4 <- function(out, input, sep = ".") {
  if (input == "j") {
    return(done(out))
  }
  paste(out, input, sep = sep)
}
letters %>% reduce(paste4)

purrr

Functional Programming Tools

v0.3.4
GPL-3 | file LICENSE
Authors
Lionel Henry [aut, cre], Hadley Wickham [aut], RStudio [cph, fnd]
Initial release

We don't support your browser anymore

Please choose more modern alternatives, such as Google Chrome or Mozilla Firefox.