-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy pathreduce.Rd
More file actions
131 lines (108 loc) · 4.62 KB
/
reduce.Rd
File metadata and controls
131 lines (108 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/reduce.R
\name{reduce}
\alias{reduce}
\alias{reduce2}
\title{Reduce a list to a single value by iteratively applying a binary function}
\usage{
reduce(.x, .f, ..., .init, .dir = c("forward", "backward"))
reduce2(.x, .y, .f, ..., .init)
}
\arguments{
\item{.x}{A list or atomic vector.}
\item{.f}{For \code{reduce()}, 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 \code{reduce2()}, a 3-argument function. The function will be passed the
accumulated value as the first argument, the next value of \code{.x} as the
second argument, and the next value of \code{.y} as the third argument.
The reduction terminates early if \code{.f} returns a value wrapped in
a \code{\link[=done]{done()}}.}
\item{...}{Additional arguments passed on to the reduce function.
We now generally recommend against using \code{...} to pass additional
(constant) arguments to \code{.f}. Instead use a shorthand anonymous function:
\if{html}{\out{<div class="sourceCode R">}}\preformatted{# Instead of
x |> reduce(f, 1, 2, collapse = ",")
# do:
x |> reduce(\\(x, y) f(x, y, 1, 2, collapse = ","))
}\if{html}{\out{</div>}}
This makes it easier to understand which arguments belong to which
function and will tend to yield better error messages.}
\item{.init}{If supplied, will be used as the first value to start
the accumulation, rather than using \code{.x[[1]]}. This is useful if
you want to ensure that \code{reduce} returns a correct value when \code{.x}
is empty. If missing, and \code{.x} is empty, will throw an error.}
\item{.dir}{The direction of reduction as a string, one of
\code{"forward"} (the default) or \code{"backward"}. See the section about
direction below.}
\item{.y}{For \code{reduce2()} an additional
argument that is passed to \code{.f}. If \code{init} is not set, \code{.y}
should be 1 element shorter than \code{.x}.}
}
\description{
\code{reduce()} is an operation that combines the elements of a vector
into a single value. The combination is driven by \code{.f}, a binary
function that takes two values and returns a single value: reducing
\code{f} over \code{1:3} computes the value \code{f(f(1, 2), 3)}.
}
\section{Direction}{
When \code{.f} is an associative operation like \code{+} or \code{c()}, the
direction of reduction does not matter. For instance, reducing the
vector \code{1:3} with the binary function \code{+} computes the sum \code{((1 + 2) + 3)} from the left, and the same sum \code{(1 + (2 + 3))} from the
right.
In other cases, the direction has important consequences on the
reduced value. For instance, reducing a vector with \code{list()} from
the left produces a left-leaning nested list (or tree), while
reducing \code{list()} from the right produces a right-leaning list.
}
\examples{
# Reducing `+` computes the sum of a vector while reducing `*`
# computes the product:
1:3 |> reduce(`+`)
1:10 |> reduce(`*`)
# By ignoring the input vector (nxt), you can turn output of one step into
# the input for the next. This code takes 10 steps of a random walk:
reduce(1:10, \(acc, nxt) acc + rnorm(1), .init = 0)
# 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)
}
\seealso{
\code{\link[=accumulate]{accumulate()}} for a version that returns all intermediate
values of the reduction.
}