Movatterモバイル変換


[0]ホーム

URL:


Title:Functional Programming Tools
Version:1.2.0
Description:A complete and consistent functional programming toolkit for R.
License:MIT + file LICENSE
URL:https://purrr.tidyverse.org/,https://github.com/tidyverse/purrr
BugReports:https://github.com/tidyverse/purrr/issues
Depends:R (≥ 4.1)
Imports:cli (≥ 3.6.1), lifecycle (≥ 1.0.3), magrittr (≥ 1.5.0),rlang (≥ 1.1.1), vctrs (≥ 0.6.3)
Suggests:carrier (≥ 0.3.0), covr, dplyr (≥ 0.7.8), httr, knitr,lubridate, mirai (≥ 2.5.1), rmarkdown, testthat (≥ 3.0.0),tibble, tidyselect
LinkingTo:cli
VignetteBuilder:knitr
Biarch:true
Config/build/compilation-database:true
Config/Needs/website:tidyverse/tidytemplate, tidyr
Config/testthat/edition:3
Config/testthat/parallel:TRUE
Encoding:UTF-8
RoxygenNote:7.3.3
NeedsCompilation:yes
Packaged:2025-11-03 22:03:33 UTC; hadleywickham
Author:Hadley WickhamORCID iD [aut, cre], Lionel Henry [aut], Posit Software, PBCROR ID [cph, fnd]
Maintainer:Hadley Wickham <hadley@posit.co>
Repository:CRAN
Date/Publication:2025-11-04 13:20:02 UTC

purrr: Functional Programming Tools

Description

logo

A complete and consistent functional programming toolkit for R.

Author(s)

Maintainer: Hadley Wickhamhadley@posit.co (ORCID)

Authors:

Other contributors:

See Also

Useful links:


Pipe operator

Description

Pipe operator

Usage

lhs %>% rhs

Accumulate intermediate results of a vector reduction

Description

accumulate() sequentially applies a 2-argument function to elements of avector. Each application of the function uses the initial value or resultof the previous application as the first argument. The second argument isthe next value of the vector. The results of each application arereturned in a list. The accumulation can optionally terminate beforeprocessing the whole vector in response to adone() signal returned bythe accumulation function.

By contrast toaccumulate(),reduce() applies a 2-argument function inthe same way, but discards all results except that of the final functionapplication.

accumulate2() sequentially applies a function to elements of two lists,.x and.y.

Usage

accumulate(  .x,  .f,  ...,  .init,  .dir = c("forward", "backward"),  .simplify = NA,  .ptype = NULL)accumulate2(.x, .y, .f, ..., .init, .simplify = NA, .ptype = NULL)

Arguments

.x

A list or atomic vector.

.f

Foraccumulate().f is 2-argument function. The function willbe passed the accumulated result or initial value as the first argument.The next value in sequence is passed as the second argument.

Foraccumulate2(), a 3-argument function. Thefunction will be passed the accumulated result as the firstargument. The next value in sequence from.x is passed as the second argument. Thenext value in sequence from.y is passed as the third argument.

The accumulation terminates early if.f returns a value wrapped inadone().

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.init

If supplied, will be used as the first value to startthe accumulation, rather than using.x[[1]]. This is useful ifyou want to ensure thatreduce returns a correct value when.xis empty. If missing, and.x is empty, will throw an error.

.dir

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

.simplify

IfNA, the default, the accumulated list ofresults is simplified to an atomic vector if possible.IfTRUE, the result is simplified, erroring if not possible.IfFALSE, the result is not simplified, always returning a list.

.ptype

Ifsimplify isNA orTRUE, optionally supply a vectorprototype to enforce the output type.

.y

Foraccumulate2().y is the second argument of the pair. Itneeds to be 1 element shorter than the vector to be accumulated (.x).If.init is set,.y needs to be one element shorted than theconcatenation of the initial value and.x.

Value

A vector the same length of.x with the same names as.x.

If.init is supplied, the length is extended by 1. If.x hasnames, the initial value is given the name".init", otherwisethe returned vector is kept unnamed.

If.dir is"forward" (the default), the first element is theinitial value (.init if supplied, or the first element of.x)and the last element is the final reduced value. In case of aright accumulation, this order is reversed.

The accumulation terminates early if.f returns a value wrappedin adone(). If the done box is empty, the last value isused instead and the result is one element shorter (but alwaysincludes the initial value, even when terminating at the firstiteration).

Direction

When.f is an associative operation like+ orc(), thedirection of reduction does not matter. For instance, reducing thevector1:3 with the binary function+ computes the sum((1 + 2) + 3) from the left, and the same sum(1 + (2 + 3)) from theright.

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

See Also

reduce() when you only need the final reduced value.

Examples

# With an associative operation, the final value is always the# same, no matter the direction. You'll find it in the first element for a# backward (left) accumulation, and in the last element for forward# (right) one:1:5 |> accumulate(`+`)1:5 |> accumulate(`+`, .dir = "backward")# The final value is always equal to the equivalent reduction:1:5 |> reduce(`+`)# It is easier to understand the details of the reduction with# `paste()`.accumulate(letters[1:5], paste, sep = ".")# Note how the intermediary reduced values are passed to the left# with a left reduction, and to the right otherwise:accumulate(letters[1:5], paste, sep = ".", .dir = "backward")# 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:accumulate(1:10, \(acc, nxt) acc + rnorm(1), .init = 0)# `accumulate2()` is a version of `accumulate()` that works with# 3-argument functions and one additional vector:paste2 <- function(acc, nxt, sep = ".") paste(acc, nxt, sep = sep)letters[1:4] |> accumulate(paste2)letters[1:4] |> accumulate2(c("-", ".", "-"), paste2)# You can shortcircuit an accumulation 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 |> accumulate(paste3)# Note how we get twice the same value in the accumulation. That's# because we have returned it twice. To prevent this, return an empty# done box to signal to accumulate() that it should terminate with the# value of the last iteration:paste3 <- function(out, input, sep = ".") {  if (nchar(out) > 4) {    return(done())  }  paste(out, input, sep = sep)}letters |> accumulate(paste3)# Here the early return branch checks the incoming inputs passed on# the RHS:paste4 <- function(out, input, sep = ".") {  if (input == "f") {    return(done())  }  paste(out, input, sep = sep)}letters |> accumulate(paste4)# Simulating stochastic processes with drift## Not run: library(dplyr)library(ggplot2)map(1:5, \(i) rnorm(100)) |>  set_names(paste0("sim", 1:5)) |>  map(\(l) accumulate(l, \(acc, nxt) .05 + acc + nxt)) |>  map(\(x) tibble(value = x, step = 1:100)) |>  list_rbind(names_to = "simulation") |>  ggplot(aes(x = step, y = value)) +    geom_line(aes(color = simulation)) +    ggtitle("Simulations of a random walk with drift")## End(Not run)

Create a list of given length

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 since it's not related to thecore purpose of purrr.

It can be useful to create an empty list that you plan to fill later. This issimilar to the idea ofseq_along(), which creates a vector of the samelength as its input.

Usage

list_along(x)

Arguments

x

A vector.

Value

A list of the same length asx.

Examples

x <- 1:5seq_along(x)list_along(x)

Coerce array to list

Description

array_branch() andarray_tree() enable arrays to beused with purrr's functionals by turning them into lists. Thedetails of the coercion are controlled by themarginargument.array_tree() creates an hierarchical list (a tree)that has as many levels as dimensions specified inmargin,whilearray_branch() creates a flat list (by analogy, abranch) along all mentioned dimensions.

Usage

array_branch(array, margin = NULL)array_tree(array, margin = NULL)

Arguments

array

An array to coerce into a list.

margin

A numeric vector indicating the positions of theindices to be to be enlisted. IfNULL, a full margin isused. Ifnumeric(0), the array as a whole is wrapped in alist.

Details

When no margin is specified, all dimensions are used bydefault. Whenmargin is a numeric vector of length zero, thewhole array is wrapped in a list.

Examples

# We create an array with 3 dimensionsx <- array(1:12, c(2, 2, 3))# A full margin for such an array would be the vector 1:3. This is# the default if you don't specify a margin# Creating a branch along the full margin is equivalent to# as.list(array) and produces a list of size length(x):array_branch(x) |> str()# A branch along the first dimension yields a list of length 2# with each element containing a 2x3 array:array_branch(x, 1) |> str()# A branch along the first and third dimensions yields a list of# length 2x3 whose elements contain a vector of length 2:array_branch(x, c(1, 3)) |> str()# Creating a tree from the full margin creates a list of lists of# lists:array_tree(x) |> str()# The ordering and the depth of the tree are controlled by the# margin argument:array_tree(x, c(3, 1)) |> str()

Convert an object into a mapper function

Description

as_mapper is the powerhouse behind the varied functionspecifications that most purrr functions allow. It is an S3generic. The default method forwards its arguments torlang::as_function().

Usage

as_mapper(.f, ...)## S3 method for class 'character'as_mapper(.f, ..., .null, .default = NULL)## S3 method for class 'numeric'as_mapper(.f, ..., .null, .default = NULL)## S3 method for class 'list'as_mapper(.f, ..., .null, .default = NULL)

Arguments

.f

A function, formula, or vector (not necessarily atomic).

If afunction, it is used as is.

If aformula, e.g.~ .x + 2, it is converted to a function.No longer recommended.

Ifcharacter vector,numeric vector, orlist, it isconverted to an extractor function. Character vectors index byname and numeric vectors index by position; use a list to indexby position and name at different levels. If a component is notpresent, the value of.default will be returned.

...

Additional arguments passed on to methods.

.default,.null

Optional additional argument for extractor functions(i.e. when.f is character, integer, or list). Returned whenvalue is absent (does not exist) or empty (has length 0)..null is deprecated; please use.default instead.

Examples

as_mapper(\(x) x + 1)as_mapper(1)as_mapper(c("a", "b", "c"))# Equivalent to function(x) x[["a"]][["b"]][["c"]]as_mapper(list(1, "a", 2))# Equivalent to function(x) x[[1]][["a"]][[2]]as_mapper(list(1, attr_getter("a")))# Equivalent to function(x) attr(x[[1]], "a")as_mapper(c("a", "b", "c"), .default = NA)

Coerce a list to a vector

Description

[Superseded]

These functions were superseded in purrr 1.0.0 in favour oflist_simplify() which has more consistent semantics based on vctrsprinciples:

Superseded functions will not go away, but will only receive criticalbug fixes.

Usage

as_vector(.x, .type = NULL)simplify(.x, .type = NULL)simplify_all(.x, .type = NULL)

Arguments

.x

A list of vectors

.type

Can be a vector mold specifying both the type and thelength of the vectors to be concatenated, such asnumeric(1)orinteger(4). Alternatively, it can be a string describingthe type, one of: "logical", "integer", "double", "complex","character" or "raw".

Examples

# wasas.list(letters) |> as_vector("character")# nowas.list(letters) |> list_simplify(ptype = character())# was:list(1:2, 3:4, 5:6) |> as_vector(integer(2))# now:list(1:2, 3:4, 5:6) |> list_c(ptype = integer())

Create an attribute getter function

Description

attr_getter() generates an attribute accessor function; i.e., itgenerates a function for extracting an attribute with a givenname. Unlike the base Rattr() function with default options, itdoesn't use partial matching.

Usage

attr_getter(attr)

Arguments

attr

An attribute name as string.

See Also

pluck()

Examples

# attr_getter() takes an attribute name and returns a function to# access the attribute:get_rownames <- attr_getter("row.names")get_rownames(mtcars)# These getter functions are handy in conjunction with pluck() for# extracting deeply into a data structure. Here we'll first# extract by position, then by attribute:obj1 <- structure("obj", obj_attr = "foo")obj2 <- structure("obj", obj_attr = "bar")x <- list(obj1, obj2)pluck(x, 1, attr_getter("obj_attr"))  # From first objectpluck(x, 2, attr_getter("obj_attr"))  # From second object

Wrap a function so it will automaticallybrowse() on error

Description

A function wrapped withauto_browse() will automatically enter aninteractive debugger usingbrowser() when ever it encounters an error.

Usage

auto_browse(.f)

Arguments

.f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:compose(),insistently(),negate(),partial(),possibly(),quietly(),safely(),slowly()

Examples

# For interactive usage, auto_browse() is useful because it automatically# starts a browser() in the right place.f <- function(x) {  y <- 20  if (x > 5) {    stop("!")  } else {    x  }}if (interactive()) {  map(1:6, auto_browse(f))}

Get an element deep within a nested data structure, failing if it doesn'texist

Description

chuck() implements a generalised form of[[ that allow you to indexdeeply and flexibly into data structures. If the index you are trying toaccess does not exist (or isNULL), it will throw (i.e. chuck) an error.

Usage

chuck(.x, ...)

Arguments

.x

A vector or environment

...

A list of accessors for indexing into the object. Can bean positive integer, a negative integer (to index from the right),a string (to index into names), or an accessor function(except for the assignment variants which only support names andpositions). If the object being indexed is an S4 object,accessing it by name will return the corresponding slot.

Dynamic dots are supported. In particular, ifyour accessors are stored in a list, you can splice that in with⁠!!!⁠.

See Also

pluck() for a quiet equivalent.

Examples

x <- list(a = 1, b = 2)# When indexing an element that doesn't exist `[[` sometimes returns NULL:x[["y"]]# and sometimes errors:try(x[[3]])# chuck() consistently errors:try(chuck(x, "y"))try(chuck(x, 3))

Compose multiple functions together to create a new function

Description

Create a new function that is the composition of multiple functions,i.e.compose(f, g) is equivalent tofunction(...) f(g(...)).

Usage

compose(..., .dir = c("backward", "forward"))

Arguments

...

Functions to apply in order (from right to left bydefault). Formulas are converted to functions in the usual way.

Dynamic dots are supported. In particular, ifyour functions are stored in a list, you can splice that in with⁠!!!⁠.

.dir

If"backward" (the default), the functions are calledin the reverse order, from right to left, as is conventional inmathematics. If"forward", they are called from left to right.

Value

A function

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),insistently(),negate(),partial(),possibly(),quietly(),safely(),slowly()

Examples

not_null <- compose(`!`, is.null)not_null(4)not_null(NULL)add1 <- function(x) x + 1compose(add1, add1)(8)fn <- compose(\(x) paste(x, "foo"), \(x) paste(x, "bar"))fn("input")# Lists of functions can be spliced with !!!fns <- list(  function(x) paste(x, "foo"),  \(x) paste(x, "bar"))fn <- compose(!!!fns)fn("input")

Produce all combinations of list elements

Description

[Deprecated]

These functions were deprecated in purrr 1.0.0 because theyare slow and buggy, and we no longer think they are the rightapproach to solving this problem. Please usetidyr::expand_grid()instead.

Here is an example of equivalent usages forcross() andexpand_grid():

data <- list(  id = c("John", "Jane"),  sep = c("! ", "... "),  greeting = c("Hello.", "Bonjour."))# With deprecated `cross()`data |> cross() |> map_chr(\(...) paste0(..., collapse = ""))# With `expand_grid()`tidyr::expand_grid(!!!data) |> pmap_chr(paste)

Usage

cross(.l, .filter = NULL)cross2(.x, .y, .filter = NULL)cross3(.x, .y, .z, .filter = NULL)cross_df(.l, .filter = NULL)

Arguments

.l

A list of lists or atomic vectors. Alternatively, a dataframe.cross_df() requires all elements to be named.

.filter

A predicate function that takes the same number ofarguments as the number of variables to be combined.

.x,.y,.z

Lists or atomic vectors.

Details

cross2() returns the product set of the elements of.x and.y.cross3() takes an additional.z argument.cross() takes a list.l andreturns the cartesian product of all its elements in a list, withone combination by element.cross_df() is likecross() but returns a data frame, with one combination byrow.

cross(),cross2() andcross3() return thecartesian product is returned in wide format. This makes it moreamenable to mapping operations.cross_df() returns the outputin long format just asexpand.grid() does. This is adaptedto rowwise operations.

When the number of combinations is large and the individualelements are heavy memory-wise, it is often useful to filterunwanted combinations on the fly with.filter. It must bea predicate function that takes the same number of arguments as thenumber of crossed objects (2 forcross2(), 3 forcross3(),length(.l) forcross()) andreturnsTRUE orFALSE. The combinations where thepredicate function returnsTRUE will be removed from theresult.

Value

cross2(),cross3() andcross()always return a list.cross_df() always returns a dataframe.cross() returns a list where each element is onecombination so that the list can be directly mappedover.cross_df() returns a data frame where each row is onecombination.

See Also

expand.grid()

Examples

# We build all combinations of names, greetings and separators from our# list of data and pass each one to paste()data <- list(  id = c("John", "Jane"),  greeting = c("Hello.", "Bonjour."),  sep = c("! ", "... "))data |>  cross() |>  map(lift(paste))# cross() returns the combinations in long format: many elements,# each representing one combination. With cross_df() we'll get a# data frame in long format: crossing three objects produces a data# frame of three columns with each row being a particular# combination. This is the same format that expand.grid() returns.args <- data |> cross_df()# In case you need a list in long format (and not a data frame)# just run as.list() after cross_df()args |> as.list()# This format is often less practical for functional programming# because applying a function to the combinations requires a loopout <- vector("character", length = nrow(args))for (i in seq_along(out))  out[[i]] <- invoke("paste", map(args, i))out# It's easier to transpose and then use invoke_map()args |> transpose() |> map_chr(\(x) exec(paste, !!!x))# Unwanted combinations can be filtered out with a predicate functionfilter <- function(x, y) x >= ycross2(1:5, 1:5, .filter = filter) |> str()# To give names to the components of the combinations, we map# setNames() on the product:x <- seq_len(3)cross2(x, x, .filter = `==`) |>  map(setNames, c("x", "y"))# Alternatively we can encapsulate the arguments in a named list# before crossing to get named components:list(x = x, y = x) |>  cross(.filter = `==`)

Find the value or position of the first match

Description

Find the value or position of the first match

Usage

detect(.x, .f, ..., .dir = c("forward", "backward"), .default = NULL)detect_index(.x, .f, ..., .dir = c("forward", "backward"))

Arguments

.x

A list or vector.

.f

A function, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. Use.x to refer to the first argument. Nolonger recommended.

  • A string, integer, or list, e.g."idx",1, orlist("idx", 1) whichare shorthand for⁠\(x) pluck(x, "idx")⁠,⁠\(x) pluck(x, 1)⁠, and⁠\(x) pluck(x, "idx", 1)⁠ respectively. Optionally supply.default toset a default value if the indexed element isNULL or does not exist.

...

Additional arguments passed on to.p.

.dir

If"forward", the default, starts at the beginning ofthe vector and move towards the end; if"backward", starts atthe end of the vector and moves towards the beginning.

.default

The value returned when nothing is detected.

Value

detect the value of the first item that matches thepredicate;detect_index the position of the matching item.If not found,detect returnsNULL anddetect_indexreturns 0.

See Also

keep() for keeping all matching values.

Examples

is_even <- function(x) x %% 2 == 03:10 |> detect(is_even)3:10 |> detect_index(is_even)3:10 |> detect(is_even, .dir = "backward")3:10 |> detect_index(is_even, .dir = "backward")# Since `.f` is passed to as_mapper(), you can supply a pluck object:x <- list(  list(1, foo = FALSE),  list(2, foo = TRUE),  list(3, foo = TRUE))detect(x, "foo")detect_index(x, "foo")# If you need to find all values, use keep():keep(x, "foo")# If you need to find all positions, use map_lgl():which(map_lgl(x, "foo"))

Do every, some, or none of the elements of a list satisfy a predicate?

Description

Usage

every(.x, .p, ...)some(.x, .p, ...)none(.x, .p, ...)

Arguments

.x

A list or vector.

.p

A predicate function (i.e. a function that returns eitherTRUEorFALSE) specified in one of the following ways:

  • A named function, e.g.is.character.

  • An anonymous function, e.g.⁠\(x) all(x < 0)⁠ orfunction(x) all(x < 0).

  • A formula, e.g.~ all(.x < 0). Use.x to refer to the first argument.No longer recommended.

...

Additional arguments passed on to.p.

Value

A logical vector of length 1.

Examples

x <- list(0:10, 5.5)x |> every(is.numeric)x |> every(is.integer)x |> some(is.integer)x |> none(is.character)# Missing values are propagated:some(list(NA, FALSE), identity)# If you need to use these functions in a context where missing values are# unsafe (e.g. in `if ()` conditions), make sure to use safe predicates:if (some(list(NA, FALSE), rlang::is_true)) "foo" else "bar"

Best practices for exporting adverb-wrapped functions

Description

Exporting functions created with purrr adverbs in your packagerequires some precautions because the functions will contain internalpurrr code. This means that creating them once and for all whenthe package is built may cause problems when purrr is updated, becausea function that the adverb uses might no longer exist.

Instead, either create the modified function once per session on packageload or wrap the call within another function every time you use it:


Flatten a list of lists into a simple vector

Description

[Superseded]

These functions were superseded in purrr 1.0.0 because their behaviour wasinconsistent. Superseded functions will not go away, but will only receivecritical bug fixes.

Usage

flatten(.x)flatten_lgl(.x)flatten_int(.x)flatten_dbl(.x)flatten_chr(.x)flatten_dfr(.x, .id = NULL)flatten_dfc(.x)

Arguments

.x

A list to flatten. The contents of the list can be anything forflatten() (as a list is returned), but the contents must match thetype for the other functions.

Value

flatten() returns a list,flatten_lgl() a logicalvector,flatten_int() an integer vector,flatten_dbl() adouble vector, andflatten_chr() a character vector.

flatten_dfr() andflatten_dfc() return data frames created byrow-binding and column-binding respectively. They require dplyr tobe installed.

Examples

x <- map(1:3, \(i) sample(4))x# wasx |> flatten_int() |> str()# nowx |> list_c() |> str()x <- list(list(1, 2), list(3, 4))# wasx |> flatten() |> str()# nowx |> list_flatten() |> str()

Does a list contain an object?

Description

Does a list contain an object?

Usage

has_element(.x, .y)

Arguments

.x

A list or atomic vector.

.y

Object to test for

Examples

x <- list(1:10, 5, 9.9)x |> has_element(1:10)x |> has_element(3)

Find head/tail that all satisfies a predicate.

Description

Find head/tail that all satisfies a predicate.

Usage

head_while(.x, .p, ...)tail_while(.x, .p, ...)

Arguments

.x

A list or atomic vector.

.p

A single predicate function, a formula describing such apredicate function, or a logical vector of the same length as.x.Alternatively, if the elements of.x are themselves lists ofobjects, a string indicating the name of a logical element in theinner lists. Only those elements where.p evaluates toTRUE will be modified.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

Value

A vector the same type as.x.

Examples

pos <- function(x) x >= 0head_while(5:-5, pos)tail_while(5:-5, negate(pos))big <- function(x) x > 100head_while(0:10, big)tail_while(0:10, big)

Apply a function to each element of a vector, and its index

Description

imap(x, ...), an indexed map, is short hand formap2(x, names(x), ...) ifx has names, ormap2(x, seq_along(x), ...)if it does not. This is useful if you need to compute on both the valueand the position of an element.

Usage

imap(.x, .f, ...)imap_lgl(.x, .f, ...)imap_chr(.x, .f, ...)imap_int(.x, .f, ...)imap_dbl(.x, .f, ...)imap_vec(.x, .f, ...)iwalk(.x, .f, ...)

Arguments

.x

A list or atomic vector.

.f

A function, specified in one of the following ways:

  • A named function, e.g.paste.

  • An anonymous function, e.g.⁠\(x, idx) x + idx⁠ orfunction(x, idx) x + idx.

  • A formula, e.g.~ .x + .y. Use.x to refer to the current element and.y to refer to the current index. No longer recommended.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

Value

A vector the same length as.x.

See Also

Other map variants:lmap(),map(),map2(),map_depth(),map_if(),modify(),pmap()

Examples

imap_chr(sample(10), paste)imap_chr(sample(10), \(x, idx) paste0(idx, ": ", x))iwalk(mtcars, \(x, idx) cat(idx, ": ", median(x), "\n", sep = ""))

Parallelization in purrr

Description

[Experimental]

All map functions allow parallelized operation usingmirai.

Wrap functions passed to the.f argument ofmap() and its variants within_parallel().

in_parallel() is apurrr adverb that plays two roles:

For maps to actually be performed in parallel, the user must also setmirai::daemons(), otherwise they fall back to sequential processing.mirai::require_daemons() may be used to enforce the use of parallelprocessing. See the section 'Daemons settings' below.

Usage

in_parallel(.f, ...)

Arguments

.f

A fresh formula or function. "Fresh" here means that they should bedeclared in the call toin_parallel().

...

Named arguments to declare in the environment of the function.

Value

A 'crate' (classed function).

Creating self-contained functions

in_parallel() is a simple wrapper ofcarrier::crate() and you may referto that package for more details.

Example usage:

# The function needs to be freshly-defined, so instead of:mtcars |> map_dbl(in_parallel(sum))# Use an anonymous function:mtcars |> map_dbl(in_parallel(\(x) sum(x)))# Package functions need to be explicitly namespaced, so instead of:map(1:3, in_parallel(\(x) vec_init(integer(), x)))# Use :: to namespace all package functions:map(1:3, in_parallel(\(x) vctrs::vec_init(integer(), x)))fun <- function(x) { param + helper(x) }helper <- function(x) { x %% 2 }param <- 5# Operating in parallel, locally-defined functions, including helper# functions and other objects required by it, will not be found:map(1:3, in_parallel(\(x) fun(x)))# Use the ... argument to supply these objects:map(1:3, in_parallel(\(x) fun(x), fun = fun, helper = helper, param = param))

When to use

Parallelizing a map using 'n' processes does not automatically lead to ittaking 1/n of the time. Additional overhead from setting up the parallel taskand communicating with parallel processes eats into this benefit, and canoutweigh it for very short tasks or those involving large amounts of data.

The threshold at which parallelization becomes clearly beneficial will differaccording to your individual setup and task, but a rough guide would be inthe order of 100 microseconds to 1 millisecond for each map iteration.

Daemons settings

How and where parallelization occurs is determined bymirai::daemons().This is a function from themirai package that sets up daemons(persistent background processes that receive parallel computations) on yourlocal machine or across the network.

Daemons must be set prior to performing any parallel map operation, otherwisein_parallel() will fall back to sequential processing. To ensure that mapsare always performed in parallel, placemirai::require_daemons() before themap.

It is usual to set daemons once per session. You can leave them running onyour local machine as they consume almost no resources whilst waiting toreceive tasks. The following sets up 6 daemons locally:

mirai::daemons(6)

Function arguments:

Resetting daemons:

Daemons persist for the duration of your session. To reset and tear down anyexisting daemons:

mirai::daemons(0)

All daemons automatically terminate when your session ends. You do not needto explicitly terminate daemons in this instance, although it is still goodpractice to do so.

Note: if you are using parallel map within a package, do not make anymirai::daemons() calls within the package. This is as it should always beup to the user how they wish to set up parallel processing: (i) resources areonly known at run-time e.g. availability of local or remote daemons, (ii)packages should make use of existing daemons when already set, rather thanreset them, and (iii) it helps prevent inadvertently spawning too manydaemons when functions are used recursively within each other.

References

purrr's parallelization is powered bymirai. See themirai website for more details.

See Also

map() for usage examples.

Examples

# Run in interactive sessions only as spawns additional processesdefault_param <- 0.5delay <- function(secs = default_param) {  Sys.sleep(secs)}slow_lm <- function(formula, data) {  delay()  lm(formula, data)}# Example of a 'crate' returned by in_parallel(). The object print method# shows the size of the crate and any objects contained within:crate <- in_parallel(  \(df) slow_lm(mpg ~ disp, data = df),  slow_lm = slow_lm,  delay = delay,  default_param = default_param)crate# Use mirai::mirai() to test that a crate is self-contained# by running it in a daemon and collecting its return value:mirai::mirai(crate(mtcars), crate = crate) |> mirai::collect_mirai()

Transform a function to wait then retry after an error

Description

insistently() takes a function and modifies it to retry after givenamount of time whenever it errors.

Usage

insistently(f, rate = rate_backoff(), quiet = TRUE)

Arguments

f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

rate

Arate object. Defaults to jittered exponentialbackoff.

quiet

Hide errors (TRUE, the default), or display themas they occur?

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

httr::RETRY() is a special case ofinsistently() forHTTP verbs.

Other adverbs:auto_browse(),compose(),negate(),partial(),possibly(),quietly(),safely(),slowly()

Examples

# For the purpose of this example, we first create a custom rate# object with a low waiting time between attempts:rate <- rate_delay(0.1)# insistently() makes a function repeatedly try to workrisky_runif <- function(lo = 0, hi = 1) {  y <- runif(1, lo, hi)  if(y < 0.9) {    stop(y, " is too small")  }  y}# Let's now create an exponential backoff rate with a low waiting# time between attempts:rate <- rate_backoff(pause_base = 0.1, pause_min = 0.005, max_times = 4)# Modify your function to run insistently.insistent_risky_runif <- insistently(risky_runif, rate, quiet = FALSE)set.seed(6) # Succeeding seedinsistent_risky_runif()set.seed(3) # Failing seedtry(insistent_risky_runif())# You can also use other types of rate settings, like a delay rate# that waits for a fixed amount of time. Be aware that a delay rate# has an infinite amount of attempts by default:rate <- rate_delay(0.2, max_times = 3)insistent_risky_runif <- insistently(risky_runif, rate = rate, quiet = FALSE)try(insistent_risky_runif())# insistently() and possibly() are a useful combinationrate <- rate_backoff(pause_base = 0.1, pause_min = 0.005)possibly_insistent_risky_runif <- possibly(insistent_risky_runif, otherwise = -99)set.seed(6)possibly_insistent_risky_runif()set.seed(3)possibly_insistent_risky_runif()

Invoke functions.

Description

[Deprecated]

These functions were superded in purrr 0.3.0 and deprecated in purrr 1.0.0.

Usage

invoke(.f, .x = NULL, ..., .env = NULL)invoke_map(.f, .x = list(NULL), ..., .env = NULL)invoke_map_lgl(.f, .x = list(NULL), ..., .env = NULL)invoke_map_int(.f, .x = list(NULL), ..., .env = NULL)invoke_map_dbl(.f, .x = list(NULL), ..., .env = NULL)invoke_map_chr(.f, .x = list(NULL), ..., .env = NULL)invoke_map_raw(.f, .x = list(NULL), ..., .env = NULL)invoke_map_dfr(.f, .x = list(NULL), ..., .env = NULL)invoke_map_dfc(.f, .x = list(NULL), ..., .env = NULL)

Arguments

.f

Forinvoke, a function; forinvoke_map alist of functions.

.x

Forinvoke, an argument-list; forinvoke_map alist of argument-lists the same length as.f (or length 1).The default argument,list(NULL), will be recycled to thesame length as.f, and will call each function with noarguments (apart from any supplied in....

...

Additional arguments passed to each function.

.env

Environment in whichdo.call() shouldevaluate a constructed expression. This only matters if you passas.f the name of a function rather than its value, or as.x symbols of objects rather than their values.

Examples

# wasinvoke(runif, list(n = 10))invoke(runif, n = 10)# nowexec(runif, n = 10)# wasargs <- list("01a", "01b")invoke(paste, args, sep = "-")# nowexec(paste, !!!args, sep = "-")# wasfuns <- list(runif, rnorm)funs |> invoke_map(n = 5)funs |> invoke_map(list(list(n = 10), list(n = 5)))# nowfuns |> map(exec, n = 5)funs |> map2(list(list(n = 10), list(n = 5)), function(f, args) exec(f, !!!args))# or use pmap + a tibbledf <- tibble::tibble(  fun = list(runif, rnorm),  args = list(list(n = 10), list(n = 5)))df |> pmap(function(fun, args) exec(fun, !!!args))# waslist(m1 = mean, m2 = median) |> invoke_map(x = rcauchy(100))# nowlist(m1 = mean, m2 = median) |> map(function(f) f(rcauchy(100)))

Keep/discard elements based on their values

Description

keep() selects all elements where.p evaluates toTRUE;discard() selects all elements where.p evaluates toFALSE.compact() discards elements where.p evaluates to an empty vector.

Usage

keep(.x, .p, ...)discard(.x, .p, ...)compact(.x, .p = identity)

Arguments

.x

A list or vector.

.p

A predicate function (i.e. a function that returns eitherTRUEorFALSE) specified in one of the following ways:

  • A named function, e.g.is.character.

  • An anonymous function, e.g.⁠\(x) all(x < 0)⁠ orfunction(x) all(x < 0).

  • A formula, e.g.~ all(.x < 0). Use.x to refer to the first argument.No longer recommended.

...

Additional arguments passed on to.p.

Details

In other languages,keep() anddiscard() are often calledselect()/filter() andreject()/drop(), but those names are already takenin R.keep() is similar toFilter(), but the argument order is moreconvenient, and the evaluation of the predicate function.p is stricter.

See Also

keep_at()/discard_at() to keep/discard elements by name.

Examples

rep(10, 10) |>  map(sample, 5) |>  keep(function(x) mean(x) > 6)# Or use shorthand formrep(10, 10) |>  map(sample, 5) |>  keep(\(x) mean(x) > 6)# Using a string instead of a function will select all list elements# where that subelement is TRUEx <- rerun(5, a = rbernoulli(1), b = sample(10))xx |> keep("a")x |> discard("a")# compact() discards elements that are NULL or that have length zerolist(a = "a", b = NULL, c = integer(0), d = NA, e = list()) |>  compact()

Keep/discard elements based on their name/position

Description

keep_at() anddiscard_at() are similar to[ ordplyr::select(): theyreturn the same type of data structure as the input, but only containingthe requested elements. (If you're looking for a function similar to[[ seepluck()/chuck()).

Usage

keep_at(x, at)discard_at(x, at)

Arguments

x

A list or atomic vector.

at

A logical, integer, or character vector giving the elementsto select. Alternatively, a function that takes a vector of names,and returns a logical, integer, or character vector of elements to select.

[Deprecated]: if the tidyselect package isinstalled, you can usevars() and tidyselect helpers to selectelements.

See Also

keep()/discard() to keep/discard elements by value.

Examples

x <- c(a = 1, b = 2, cat = 10, dog = 15, elephant = 5, e = 10)x |> keep_at(letters)x |> discard_at(letters)# Can also use a functionx |> keep_at(\(x) nchar(x) == 3)x |> discard_at(\(x) nchar(x) == 3)

Lift the domain of a function

Description

[Deprecated]

lift_xy() is a composition helper. It helps you composefunctions by lifting their domain from a kind of input to anotherkind. The domain can be changed from and to a list (l), a vector(v) and dots (d). For example,lift_ld(fun) transforms afunction taking a list to a function taking dots.

The most important of those helpers is probablylift_dl()because it allows you to transform a regular function to one thattakes a list. This is often essential for composition with purrrfunctional tools. Since this is such a common function,lift() is provided as an alias for that operation.

These functions were superseded in purrr 1.0.0 because we no longer believe"lifting" to be a mainstream operation, and we are striving to reduce purrrto its most useful core. Superseded functions will not go away, but will onlyreceive critical bug fixes.

Usage

lift(..f, ..., .unnamed = FALSE)lift_dl(..f, ..., .unnamed = FALSE)lift_dv(..f, ..., .unnamed = FALSE)lift_vl(..f, ..., .type)lift_vd(..f, ..., .type)lift_ld(..f, ...)lift_lv(..f, ...)

Arguments

..f

A function to lift.

...

Default arguments for..f. These will beevaluated only once, when the lifting factory is called.

.unnamed

IfTRUE,ld orlv will notname the parameters in the lifted function signature. Thisprevents matching of arguments by name and match by positioninstead.

.type

Can be a vector mold specifying both the type and thelength of the vectors to be concatenated, such asnumeric(1)orinteger(4). Alternatively, it can be a string describingthe type, one of: "logical", "integer", "double", "complex","character" or "raw".

Value

A function.

from ... tolist(...) orc(...)

Here dots should be taken here in a figurative way. The liftedfunctions does not need to take dots per se. The function issimply wrapped a function indo.call(), so insteadof taking multiple arguments, it takes a single named list orvector which will be interpreted as its arguments. This isparticularly useful when you want to pass a row of a data frameor a list to a function and don't want to manually pull it apartin your function.

fromc(...) tolist(...) or...

These factories allow a function taking a vector to take a listor dots instead. The lifted function internally transforms itsinputs back to an atomic vector. purrr does not obey the usual Rcasting rules (e.g.,c(1, "2") produces a charactervector) and will produce an error if the types are notcompatible. Additionally, you can enforce a particular vectortype by supplying.type.

from list(...) to c(...) or ...

lift_ld() turns a function that takes a list into afunction that takes dots.lift_vd() does the same with afunction that takes an atomic vector. These factory functions arethe inverse operations oflift_dl() andlift_dv().

lift_vd() internally coerces the inputs of..f toan atomic vector. The details of this coercion can be controlledwith.type.

See Also

invoke()

Examples

### Lifting from ... to list(...) or c(...)x <- list(x = c(1:100, NA, 1000), na.rm = TRUE, trim = 0.9)lift_dl(mean)(x)# You can also use the lift() alias for this common operation:lift(mean)(x)# now:exec(mean, !!!x)# Default arguments can also be specified directly in lift_dl()list(c(1:100, NA, 1000)) |> lift_dl(mean, na.rm = TRUE)()# now:mean(c(1:100, NA, 1000), na.rm = TRUE)# lift_dl() and lift_ld() are inverse of each other.# Here we transform sum() so that it takes a listfun <- sum |> lift_dl()fun(list(3, NA, 4, na.rm = TRUE))# now:fun <- function(x) exec("sum", !!!x)exec(sum, 3, NA, 4, na.rm = TRUE)### Lifting from c(...) to list(...) or ...# In other situations we need the vector-valued function to take a# variable number of arguments as with pmap(). This is a job for# lift_vd():pmap_dbl(mtcars, lift_vd(mean))# nowpmap_dbl(mtcars, \(...) mean(c(...)))### Lifting from list(...) to c(...) or ...# This kind of lifting is sometimes needed for function# composition. An example would be to use pmap() with a function# that takes a list. In the following, we use some() on each row of# a data frame to check they each contain at least one element# satisfying a condition:mtcars |> pmap_lgl(lift_ld(some, partial(`<`, 200)))# nowmtcars |> pmap_lgl(\(...) any(c(...) > 200))

Modify a list

Description

list_modify() is inspired byutils::modifyList().

Usage

list_assign(.x, ..., .is_node = NULL)list_modify(.x, ..., .is_node = NULL)list_merge(.x, ..., .is_node = NULL)

Arguments

.x

List to modify.

...

New values of a list. Usezap() to remove values.

These values should be either all named or all unnamed. Wheninputs are all named, they are matched to.x by name. When theyare all unnamed, they are matched by position.

Dynamic dots are supported. In particular, if yourreplacement values are stored in a list, you can splice that in with⁠!!!⁠.

.is_node

A predicate function that determines whether an element isa node (by returningTRUE) or a leaf (by returningFALSE). Thedefault value,NULL, treats simple lists as nodes and everything else(including richer objects like data frames and linear models) as leaves,usingvctrs::obj_is_list(). To recurse into all objects built on listsuseis.list().

Examples

x <- list(x = 1:10, y = 4, z = list(a = 1, b = 2))str(x)# Update valuesstr(list_assign(x, a = 1))# Replace valuesstr(list_assign(x, z = 5))str(list_assign(x, z = NULL))str(list_assign(x, z = list(a = 1:5)))# Replace recursively with list_modify(), leaving the other elements of z alonestr(list_modify(x, z = list(a = 1:5)))# Remove valuesstr(list_assign(x, z = zap()))# Combine values with list_merge()str(list_merge(x, x = 11, z = list(a = 2:5, c = 3)))# All these functions support dynamic dots features. Use !!! to splice# a list of arguments:l <- list(new = 1, y = zap(), z = 5)str(list_assign(x, !!!l))

Combine list elements into a single data structure

Description

Usage

list_c(x, ..., ptype = NULL)list_cbind(  x,  ...,  name_repair = c("unique", "universal", "check_unique"),  size = NULL)list_rbind(x, ..., names_to = rlang::zap(), ptype = NULL)

Arguments

x

A list. Forlist_rbind() andlist_cbind() the list mustonly contain only data frames orNULL.

...

These dots are for future extensions and must be empty.

ptype

An optional prototype to ensure that the output type is alwaysthe same.

name_repair

One of"unique","universal", or"check_unique".Seevctrs::vec_as_names() for the meaning of these options.

size

An optional integer size to ensure that every input has thesame size (i.e. number of rows).

names_to

By default,names(x) are lost. To keep them, supply astring tonames_to and the names will be saved into a column with thatname. Ifnames_to is supplied andx is not named, the position ofthe elements will be used instead of the names.

Examples

x1 <- list(a = 1, b = 2, c = 3)list_c(x1)x2 <- list(  a = data.frame(x = 1:2),  b = data.frame(y = "a"))list_rbind(x2)list_rbind(x2, names_to = "id")list_rbind(unname(x2), names_to = "id")list_cbind(x2)

Flatten a list

Description

Flattening a list removes a single layer of internal hierarchy,i.e. it inlines elements that are lists leaving non-lists alone.

Usage

list_flatten(  x,  ...,  is_node = NULL,  name_spec = "{outer}_{inner}",  name_repair = c("minimal", "unique", "check_unique", "universal"))

Arguments

x

A list.

...

These dots are for future extensions and must be empty.

is_node

A predicate function that determines whether an element isa node (by returningTRUE) or a leaf (by returningFALSE). Thedefault value,NULL, treats simple lists as nodes and everything else(including richer objects like data frames and linear models) as leaves,usingvctrs::obj_is_list(). To recurse into all objects built on listsuseis.list().

name_spec

If both inner and outer names are present, controlhow they are combined. Should be a glue specification that usesvariablesinner andouter.

name_repair

One of"minimal","unique","universal", or"check_unique". Seevctrs::vec_as_names() for the meaning of theseoptions.

Value

A list of the same type asx. The list might be shorterifx contains empty lists, the same length if it contains listsof length 1 or no sub-lists, or longer if it contains lists oflength > 1.

Examples

x <- list(1, list(2, 3), list(4, list(5)))x |> list_flatten() |> str()x |> list_flatten() |> list_flatten() |> str()# Flat lists are left as islist(1, 2, 3, 4, 5) |> list_flatten() |> str()# Empty lists will disappearlist(1, list(), 2, list(3)) |> list_flatten() |> str()# Another way to see this is that it reduces the depth of the listx <- list(  list(),  list(list()))x |> pluck_depth()x |> list_flatten() |> pluck_depth()# Use name_spec to control how inner and outer names are combinedx <- list(x = list(a = 1, b = 2), y = list(c = 1, d = 2))x |> list_flatten() |> names()x |> list_flatten(name_spec = "{outer}") |> names()x |> list_flatten(name_spec = "{inner}") |> names()# Set `is_node = is.list` to also flatten richer objects built on lists like# data frames and linear modelsdf <- data.frame(x = 1:3, y = 4:6)x <- list(  a_string = "something",  a_list = list(1:3, "else"),  a_df = df)x |> list_flatten(is_node = is.list)# Note that objects that are already "flat" retain their classeslist_flatten(df, is_node = is.list)

Simplify a list to an atomic or S3 vector

Description

Simplification maintains a one-to-one correspondence between the inputand output, implying that each element ofx must contain a one elementvector or a one-row data frame. If you don't want to maintain thiscorrespondence, then you probably want eitherlist_c()/list_rbind() orlist_flatten().

Usage

list_simplify(x, ..., strict = TRUE, ptype = NULL)

Arguments

x

A list.

...

These dots are for future extensions and must be empty.

strict

What should happen if simplification fails? IfTRUE(the default) it will error. IfFALSE andptype is not supplied,it will returnx unchanged.

ptype

An optional prototype to ensure that the output type is alwaysthe same.

Value

A vector the same length asx.

Examples

list_simplify(list(1, 2, 3))# Only works when vectors are length one and have compatible types:try(list_simplify(list(1, 2, 1:3)))try(list_simplify(list(1, 2, "x")))# Unless you strict = FALSE, in which case you get the input back:list_simplify(list(1, 2, 1:3), strict = FALSE)list_simplify(list(1, 2, "x"), strict = FALSE)

Transpose a list

Description

list_transpose() turns a list-of-lists "inside-out". For instance it turns a pair oflists into a list of pairs, or a list of pairs into a pair of lists. Forexample, if you had a list of lengthn where each component had valuesaandb,list_transpose() would make a list with elementsa andb that contained lists of lengthn.

It's called transpose becausex[["a"]][["b"]] is equivalent tolist_transpose(x)[["b"]][["a"]], i.e. transposing a list flips the order ofindices in a similar way to transposing a matrix.

Usage

list_transpose(  x,  ...,  template = NULL,  simplify = NA,  ptype = NULL,  default = NULL)

Arguments

x

A list of vectors to transpose.

...

These dots are for future extensions and must be empty.

template

A "template" that describes the output list. Can either bea character vector (where elements are extracted by name), or an integervector (where elements are extracted by position). Defaults to the unionof the names of the elements ofx, or if they're not present, theunion of the integer indices.

simplify

Should the result besimplified?

  • TRUE: simplify or die trying.

  • NA: simplify if possible.

  • FALSE: never try to simplify, always leaving as a list.

Alternatively, a named list specifying the simplification by outputelement.

ptype

An optional vector prototype used to control the simplification.Alternatively, a named list specifying the prototype by output element.

default

A default value to use if a value is absent orNULL.Alternatively, a named list specifying the default by output element.

Examples

# list_transpose() is useful in conjunction with safely()x <- list("a", 1, 2)y <- x |> map(safely(log))y |> str()# Put all the errors and results togethery |> list_transpose() |> str()# Supply a default result to further simplifyy |> list_transpose(default = list(result = NA)) |> str()# list_transpose() will try to simplify by default:x <- list(list(a = 1, b = 2), list(a = 3, b = 4), list(a = 5, b = 6))x |> list_transpose()# this makes list_tranpose() not completely symmetricx |> list_transpose() |> list_transpose()# use simplify = FALSE to always return lists:x |> list_transpose(simplify = FALSE) |> str()x |>  list_transpose(simplify = FALSE) |>  list_transpose(simplify = FALSE) |> str()# Provide an explicit template if you know which elements you want to extractll <- list(  list(x = 1, y = "one"),  list(z = "deux", x = 2))ll |> list_transpose()ll |> list_transpose(template = c("x", "y", "z"))ll |> list_transpose(template = 1)# And specify a default if you want to simplifyll |> list_transpose(template = c("x", "y", "z"), default = NA)

Apply a function to list-elements of a list

Description

lmap(),lmap_at() andlmap_if() are similar tomap(),map_at() andmap_if(), except instead of mapping over.x[[i]], they instead map over.x[i].

This has several advantages:

Usage

lmap(.x, .f, ...)lmap_if(.x, .p, .f, ..., .else = NULL)lmap_at(.x, .at, .f, ...)

Arguments

.x

A list or data frame.

.f

A function that takes a length-1 list and returns a list (of anylength.)

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.p

A single predicate function, a formula describing such apredicate function, or a logical vector of the same length as.x.Alternatively, if the elements of.x are themselves lists ofobjects, a string indicating the name of a logical element in theinner lists. Only those elements where.p evaluates toTRUE will be modified.

.else

A function applied to elements of.x for which.preturnsFALSE.

.at

A logical, integer, or character vector giving the elementsto select. Alternatively, a function that takes a vector of names,and returns a logical, integer, or character vector of elements to select.

[Deprecated]: if the tidyselect package isinstalled, you can usevars() and tidyselect helpers to selectelements.

Value

A list or data frame, matching.x. There are no guarantees aboutthe length.

See Also

Other map variants:imap(),map(),map2(),map_depth(),map_if(),modify(),pmap()

Examples

set.seed(1014)# Let's write a function that returns a larger list or an empty list# depending on some condition. It also uses the input name to name the# outputmaybe_rep <- function(x) {  n <- rpois(1, 2)  set_names(rep_len(x, n), paste0(names(x), seq_len(n)))}# The output size varies each time we map f()x <- list(a = 1:4, b = letters[5:7], c = 8:9, d = letters[10])x |> lmap(maybe_rep) |> str()# We can apply f() on a selected subset of xx |> lmap_at(c("a", "d"), maybe_rep) |> str()# Or only where a condition is satisfiedx |> lmap_if(is.character, maybe_rep) |> str()

Apply a function to each element of a vector

Description

The map functions transform their input by applying a function toeach element of a list or atomic vector and returning an object ofthe same length as the input.

Usage

map(.x, .f, ..., .progress = FALSE)map_lgl(.x, .f, ..., .progress = FALSE)map_int(.x, .f, ..., .progress = FALSE)map_dbl(.x, .f, ..., .progress = FALSE)map_chr(.x, .f, ..., .progress = FALSE)map_vec(.x, .f, ..., .ptype = NULL, .progress = FALSE)walk(.x, .f, ..., .progress = FALSE)

Arguments

.x

A list or atomic vector.

.f

A function, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. Use.x to refer to the firstargument. No longer recommended.

  • A string, integer, or list, e.g."idx",1, orlist("idx", 1) whichare shorthand for⁠\(x) pluck(x, "idx")⁠,⁠\(x) pluck(x, 1)⁠, and⁠\(x) pluck(x, "idx", 1)⁠ respectively. Optionally supply.default toset a default value if the indexed element isNULL or does not exist.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.progress

Whether to show a progress bar. UseTRUE to turn ona basic progress bar, use a string to give it a name, or seeprogress_bars for more details.

.ptype

IfNULL, the default, the output type is the common typeof the elements of the result. Otherwise, supply a "prototype" givingthe desired type of output.

Value

The output length is determined by the length of the input.The output names are determined by the input names.The output type is determined by the suffix:

Any errors thrown by.f will be wrapped in an error with classpurrr_error_indexed.

See Also

map_if() for applying a function to only those elementsof.x that meet a specified condition.

Other map variants:imap(),lmap(),map2(),map_depth(),map_if(),modify(),pmap()

Examples

# Compute normal distributions from an atomic vector1:10 |>  map(rnorm, n = 10)# You can also use an anonymous function1:10 |>  map(\(x) rnorm(10, x))# Simplify output to a vector instead of a list by computing the mean of the distributions1:10 |>  map(rnorm, n = 10) |>  # output a list  map_dbl(mean)           # output an atomic vector# Using set_names() with character vectors is handy to keep track# of the original inputs:set_names(c("foo", "bar")) |> map_chr(paste0, ":suffix")# Working with listsfavorite_desserts <- list(Sophia = "banana bread", Eliott = "pancakes", Karina = "chocolate cake")favorite_desserts |> map_chr(\(food) paste(food, "rocks!"))# Extract by name or position# .default specifies value for elements that are missing or NULLl1 <- list(list(a = 1L), list(a = NULL, b = 2L), list(b = 3L))l1 |> map("a", .default = "???")l1 |> map_int("b", .default = NA)l1 |> map_int(2, .default = NA)# Supply multiple values to index deeply into a listl2 <- list(  list(num = 1:3,     letters[1:3]),  list(num = 101:103, letters[4:6]),  list())l2 |> map(c(2, 2))# Use a list to build an extractor that mixes numeric indices and names,# and .default to provide a default value if the element does not existl2 |> map(list("num", 3))l2 |> map_int(list("num", 3), .default = NA)# Working with data frames# Use map_lgl(), map_dbl(), etc to return a vector instead of a list:mtcars |> map_dbl(sum)# A more realistic example: split a data frame into pieces, fit a# model to each piece, summarise and extract R^2mtcars |>  split(mtcars$cyl) |>  map(\(df) lm(mpg ~ wt, data = df)) |>  map(summary) |>  map_dbl("r.squared")# Run in interactive sessions only as spawns additional processes# To use parallelized map:# 1. Set daemons (number of parallel processes) first:mirai::daemons(2)# 2. Wrap .f with in_parallel():mtcars |> map_dbl(in_parallel(\(x) mean(x)))# Note that functions from packages should be fully qualified with `pkg::`# or call `library(pkg)` within the function1:10 |>  map(in_parallel(\(x) vctrs::vec_init(integer(), x))) |>  map_int(in_parallel(\(x) { library(vctrs); vec_size(x) }))# A locally-defined function (or any required variables)# should be passed via ... of in_parallel():slow_lm <- function(formula, data) {  Sys.sleep(0.5)  lm(formula, data)}mtcars |>  split(mtcars$cyl) |>  map(in_parallel(\(df) slow_lm(mpg ~ disp, data = df), slow_lm = slow_lm))# Tear down daemons when no longer in use:mirai::daemons(0)

Map over two inputs

Description

These functions are variants ofmap() that iterate over two arguments ata time.

Usage

map2(.x, .y, .f, ..., .progress = FALSE)map2_lgl(.x, .y, .f, ..., .progress = FALSE)map2_int(.x, .y, .f, ..., .progress = FALSE)map2_dbl(.x, .y, .f, ..., .progress = FALSE)map2_chr(.x, .y, .f, ..., .progress = FALSE)map2_vec(.x, .y, .f, ..., .ptype = NULL, .progress = FALSE)walk2(.x, .y, .f, ..., .progress = FALSE)

Arguments

.x,.y

A pair of vectors, usually the same length. If not, a vectorof length 1 will be recycled to the length of the other.

.f

A function, specified in one of the following ways:

  • A named function.

  • An anonymous function, e.g.⁠\(x, y) x + y⁠ orfunction(x, y) x + y.

  • A formula, e.g.~ .x + .y. Use.x to refer to the currentelement ofx and.y to refer to the current element ofy.No longer recommended.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.progress

Whether to show a progress bar. UseTRUE to turn ona basic progress bar, use a string to give it a name, or seeprogress_bars for more details.

.ptype

IfNULL, the default, the output type is the common typeof the elements of the result. Otherwise, supply a "prototype" givingthe desired type of output.

Value

The output length is determined by the length of the input.The output names are determined by the input names.The output type is determined by the suffix:

Any errors thrown by.f will be wrapped in an error with classpurrr_error_indexed.

See Also

Other map variants:imap(),lmap(),map(),map_depth(),map_if(),modify(),pmap()

Examples

x <- list(1, 1, 1)y <- list(10, 20, 30)map2(x, y, \(x, y) x + y)# Or justmap2(x, y, `+`)# Split into pieces, fit model to each piece, then predictby_cyl <- mtcars |> split(mtcars$cyl)mods <- by_cyl |> map(\(df) lm(mpg ~ wt, data = df))map2(mods, by_cyl, predict)

Map/modify elements at given depth

Description

map_depth() callsmap(.y, .f) on all.y at the specified.depth in.x.modify_depth() callsmodify(.y, .f) on.y at the specified.depth in.x.

Usage

map_depth(.x, .depth, .f, ..., .ragged = .depth < 0, .is_node = NULL)modify_depth(.x, .depth, .f, ..., .ragged = .depth < 0, .is_node = NULL)

Arguments

.x

A list or atomic vector.

.depth

Level of.x to map on. Use a negative value tocount up from the lowest level of the list.

  • map_depth(x, 0, fun) is equivalent tofun(x).

  • map_depth(x, 1, fun) is equivalent tox <- map(x, fun)

  • map_depth(x, 2, fun) is equivalent to⁠x <- map(x, \(y) map(y, fun))⁠

.f

A function, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. Use.x to refer to the firstargument. No longer recommended.

  • A string, integer, or list, e.g."idx",1, orlist("idx", 1) whichare shorthand for⁠\(x) pluck(x, "idx")⁠,⁠\(x) pluck(x, 1)⁠, and⁠\(x) pluck(x, "idx", 1)⁠ respectively. Optionally supply.default toset a default value if the indexed element isNULL or does not exist.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.ragged

IfTRUE, will apply to leaves, even if they're notat depth.depth. IfFALSE, will throw an error if there areno elements at depth.depth.

.is_node

A predicate function that determines whether an element isa node (by returningTRUE) or a leaf (by returningFALSE). Thedefault value,NULL, treats simple lists as nodes and everything else(including richer objects like data frames and linear models) as leaves,usingvctrs::obj_is_list(). To recurse into all objects built on listsuseis.list().

See Also

modify_tree() for a recursive version ofmodify_depth() thatallows you to apply a function to every leaf or every node.

Other map variants:imap(),lmap(),map(),map2(),map_if(),modify(),pmap()

Other modify variants:modify(),modify_tree()

Examples

# map_depth() -------------------------------------------------# Use `map_depth()` to recursively traverse nested vectors and map# a function at a certain depth:x <- list(a = list(foo = 1:2, bar = 3:4), b = list(baz = 5:6))x |> str()x |> map_depth(2, \(y) paste(y, collapse = "/")) |> str()# Equivalent to:x |> map(\(y) map(y, \(z) paste(z, collapse = "/"))) |> str()# When ragged is TRUE, `.f()` will also be passed leaves at depth < `.depth`x <- list(1, list(1, list(1, list(1, 1))))x |> str()x |> map_depth(4, \(x) length(unlist(x)), .ragged = TRUE) |> str()x |> map_depth(3, \(x) length(unlist(x)), .ragged = TRUE) |> str()x |> map_depth(2, \(x) length(unlist(x)), .ragged = TRUE) |> str()x |> map_depth(1, \(x) length(unlist(x)), .ragged = TRUE) |> str()x |> map_depth(0, \(x) length(unlist(x)), .ragged = TRUE) |> str()# modify_depth() -------------------------------------------------l1 <- list(  obj1 = list(    prop1 = list(param1 = 1:2, param2 = 3:4),    prop2 = list(param1 = 5:6, param2 = 7:8)  ),  obj2 = list(    prop1 = list(param1 = 9:10, param2 = 11:12),    prop2 = list(param1 = 12:14, param2 = 15:17)  ))# In the above list, "obj" is level 1, "prop" is level 2 and "param"# is level 3. To apply sum() on all params, we map it at depth 3:l1 |> modify_depth(3, sum) |> str()# modify() lets us pluck the elements prop1/param2 in obj1 and obj2:l1 |> modify(c("prop1", "param2")) |> str()# But what if we want to pluck all param2 elements? Then we need to# act at a lower level:l1 |> modify_depth(2, "param2") |> str()# modify_depth() can be with other purrr functions to make them operate at# a lower level. Here we ask pmap() to map paste() simultaneously over all# elements of the objects at the second level. paste() is effectively# mapped at level 3.l1 |> modify_depth(2, \(x) pmap(x, paste, sep = " / ")) |> str()

Functions that return data frames

Description

[Superseded]

Thesemap(),map2(),imap(), andpmap() variants return dataframes by row-binding or column-binding the outputs together.

The functions were superseded in purrr 1.0.0 because their namessuggest they work like⁠_lgl()⁠,⁠_int()⁠, etc which require length1 outputs, but actually they return results of any size because the resultsare combined without any size checks. Additionally, they usedplyr::bind_rows() anddplyr::bind_cols() which require dplyr to beinstalled and have confusing semantics with edge cases. Supersededfunctions will not go away, but will only receive critical bug fixes.

Instead, we recommend usingmap(),map2(), etc withlist_rbind() andlist_cbind(). These usevctrs::vec_rbind() andvctrs::vec_cbind()under the hood, and have names that more clearly reflect their semantics.

Usage

map_dfr(.x, .f, ..., .id = NULL)map_dfc(.x, .f, ...)imap_dfr(.x, .f, ..., .id = NULL)imap_dfc(.x, .f, ...)map2_dfr(.x, .y, .f, ..., .id = NULL)map2_dfc(.x, .y, .f, ...)pmap_dfr(.l, .f, ..., .id = NULL)pmap_dfc(.l, .f, ...)

Arguments

.id

Either a string orNULL. If a string, the output will containa variable with that name, storing either the name (if.x is named) orthe index (if.x is unnamed) of the input. IfNULL, the default, novariable will be created.

Only applies to⁠_dfr⁠ variant.

Examples

# map ---------------------------------------------# Was:mtcars |>  split(mtcars$cyl) |>  map(\(df) lm(mpg ~ wt, data = df)) |>  map_dfr(\(mod) as.data.frame(t(as.matrix(coef(mod)))))# Now:mtcars |>  split(mtcars$cyl) |>  map(\(df) lm(mpg ~ wt, data = df)) |>  map(\(mod) as.data.frame(t(as.matrix(coef(mod))))) |>  list_rbind()# for certain pathological inputs `map_dfr()` and `map_dfc()` actually# both combine the list by columndf <- data.frame(  x = c(" 13", "  15 "),  y = c("  34",  " 67 "))# Was:map_dfr(df, trimws)map_dfc(df, trimws)# But list_rbind()/list_cbind() fail because they require data frame inputstry(map(df, trimws) |> list_rbind())# Instead, use modify() to apply a function to each column of a data framemodify(df, trimws)# map2 ---------------------------------------------ex_fun <- function(arg1, arg2){  col <- arg1 + arg2  x <- as.data.frame(col)}arg1 <- 1:4arg2 <- 10:13# wasmap2_dfr(arg1, arg2, ex_fun)# nowmap2(arg1, arg2, ex_fun) |> list_rbind()# wasmap2_dfc(arg1, arg2, ex_fun)# nowmap2(arg1, arg2, ex_fun) |> list_cbind()

Apply a function to each element of a vector conditionally

Description

The functionsmap_if() andmap_at() take.x as input, applythe function.f to some of the elements of.x, and return alist of the same length as the input.

Usage

map_if(.x, .p, .f, ..., .else = NULL)map_at(.x, .at, .f, ..., .progress = FALSE)

Arguments

.x

A list or atomic vector.

.p

A single predicate function, a formula describing such apredicate function, or a logical vector of the same length as.x.Alternatively, if the elements of.x are themselves lists ofobjects, a string indicating the name of a logical element in theinner lists. Only those elements where.p evaluates toTRUE will be modified.

.f

A function, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. Use.x to refer to the firstargument. No longer recommended.

  • A string, integer, or list, e.g."idx",1, orlist("idx", 1) whichare shorthand for⁠\(x) pluck(x, "idx")⁠,⁠\(x) pluck(x, 1)⁠, and⁠\(x) pluck(x, "idx", 1)⁠ respectively. Optionally supply.default toset a default value if the indexed element isNULL or does not exist.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.else

A function applied to elements of.x for which.preturnsFALSE.

.at

A logical, integer, or character vector giving the elementsto select. Alternatively, a function that takes a vector of names,and returns a logical, integer, or character vector of elements to select.

[Deprecated]: if the tidyselect package isinstalled, you can usevars() and tidyselect helpers to selectelements.

.progress

Whether to show a progress bar. UseTRUE to turn ona basic progress bar, use a string to give it a name, or seeprogress_bars for more details.

See Also

Other map variants:imap(),lmap(),map(),map2(),map_depth(),modify(),pmap()

Examples

# Use a predicate function to decide whether to map a function:iris |> map_if(is.factor, as.character) |> str()# Specify an alternative with the `.else` argument:iris |> map_if(is.factor, as.character, .else = as.integer) |> str()# Use numeric vector of positions select elements to change:iris |> map_at(c(4, 5), is.numeric) |> str()# Use vector of names to specify which elements to change:iris |> map_at("Species", toupper) |> str()

Functions that return raw vectors

Description

[Deprecated]

These functions were deprecated in purrr 1.0.0 because they are of limiteduse and you can now usemap_vec() instead. They are variants ofmap(),map2(),imap(),pmap(), andflatten() that return raw vectors.

Usage

map_raw(.x, .f, ...)map2_raw(.x, .y, .f, ...)imap_raw(.x, .f, ...)pmap_raw(.l, .f, ...)flatten_raw(.x)

Modify elements selectively

Description

Unlikemap() and its variants which always return a fixed objecttype (list formap(), integer vector formap_int(), etc), themodify() family always returns the same type as the input object.

Usage

modify(.x, .f, ...)modify_if(.x, .p, .f, ..., .else = NULL)modify_at(.x, .at, .f, ...)modify2(.x, .y, .f, ...)imodify(.x, .f, ...)

Arguments

.x

A vector.

.f

A function specified in the same way as the corresponding mapfunction.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.p

A single predicate function, a formula describing such apredicate function, or a logical vector of the same length as.x.Alternatively, if the elements of.x are themselves lists ofobjects, a string indicating the name of a logical element in theinner lists. Only those elements where.p evaluates toTRUE will be modified.

.else

A function applied to elements of.x for which.preturnsFALSE.

.at

A logical, integer, or character vector giving the elementsto select. Alternatively, a function that takes a vector of names,and returns a logical, integer, or character vector of elements to select.

[Deprecated]: if the tidyselect package isinstalled, you can usevars() and tidyselect helpers to selectelements.

.y

A vector, usually the same length as.x.

Details

Since the transformation can alter the structure of the input; it'syour responsibility to ensure that the transformation produces avalid output. For example, if you're modifying a data frame,.fmust preserve the length of the input.

Value

An object the same class as.x

Genericity

modify() and variants are generic over classes that implementlength(),[[ and⁠[[<-⁠ methods. If the default implementationis not compatible for your class, you can override them with yourown methods.

If you implement your ownmodify() method, make sure it satisfiesthe following invariants:

modify(x, identity) === xmodify(x, compose(f, g)) === modify(x, g) |> modify(f)

These invariants are known as thefunctor laws in computerscience.

See Also

Other map variants:imap(),lmap(),map(),map2(),map_depth(),map_if(),pmap()

Other modify variants:map_depth(),modify_tree()

Examples

# Convert factors to charactersiris |>  modify_if(is.factor, as.character) |>  str()# Specify which columns to map with a numeric vector of positions:mtcars |> modify_at(c(1, 4, 5), as.character) |> str()# Or with a vector of names:mtcars |> modify_at(c("cyl", "am"), as.character) |> str()list(x = sample(c(TRUE, FALSE), 100, replace = TRUE), y = 1:100) |>  list_transpose(simplify = FALSE) |>  modify_if("x", \(l) list(x = l$x, y = l$y * 100)) |>  list_transpose()# Use modify2() to map over two vectors and preserve the type of# the first one:x <- c(foo = 1L, bar = 2L)y <- c(TRUE, FALSE)modify2(x, y, \(x, cond) if (cond) x else 0L)# Use a predicate function to decide whether to map a function:modify_if(iris, is.factor, as.character)# Specify an alternative with the `.else` argument:modify_if(iris, is.factor, as.character, .else = as.integer)

Modify a pluck location

Description

Usage

modify_in(.x, .where, .f, ...)assign_in(x, where, value)

Arguments

.x,x

A vector or environment

.where,where

A pluck location, as a numeric vector ofpositions, a character vector of names, or a list combining both.The location must exist in the data structure.

.f

A function to apply at the pluck location given by.where.

...

Arguments passed to.f.

value

A value to replace in.x at the pluck location.Usezap() to instead remove the element.

See Also

pluck()

Examples

# Recall that pluck() returns a component of a data structure that# might be arbitrarily deepx <- list(list(bar = 1, foo = 2))pluck(x, 1, "foo")# Use assign_in() to modify the pluck location:str(assign_in(x, list(1, "foo"), 100))# Or zap to remove itstr(assign_in(x, list(1, "foo"), zap()))# Like pluck(), this works even when the element (or its parents) don't existpluck(x, 1, "baz")str(assign_in(x, list(2, "baz"), 100))# modify_in() applies a function to that location and update the# element in place:modify_in(x, list(1, "foo"), \(x) x * 200)# Additional arguments are passed to the function in the ordinary way:modify_in(x, list(1, "foo"), `+`, 100)

Recursively modify a list

Description

modify_tree() allows you to recursively modify a list, supplying functionsthat either modify each leaf or each node (or both).

Usage

modify_tree(  x,  ...,  leaf = identity,  is_node = NULL,  pre = identity,  post = identity)

Arguments

x

A list.

...

Reserved for future use. Must be empty

leaf

A function applied to each leaf.

is_node

A predicate function that determines whether an element isa node (by returningTRUE) or a leaf (by returningFALSE). Thedefault value,NULL, treats simple lists as nodes and everything else(including richer objects like data frames and linear models) as leaves,usingvctrs::obj_is_list(). To recurse into all objects built on listsuseis.list().

pre,post

Functions applied to each node.pre is applied on theway "down", i.e. before the leaves are transformed withleaf, whilepost is applied on the way "up", i.e. after the leaves are transformed.

See Also

Other modify variants:map_depth(),modify()

Examples

x <- list(list(a = 2:1, c = list(b1 = 2), b = list(c2 = 3, c1 = 4)))x |> str()# Transform each leafx |> modify_tree(leaf = \(x) x + 100) |>  str()# Recursively sort the nodessort_named <- function(x) {  nms <- names(x)  if (!is.null(nms)) {    x[order(nms)]  } else {    x   }}x |> modify_tree(post = sort_named) |> str()

Negate a predicate function so it selects what it previously rejected

Description

Negating a function changesTRUE toFALSE andFALSE toTRUE.

Usage

negate(.p)

Arguments

.p

A predicate function (i.e. a function that returns eitherTRUEorFALSE) specified in one of the following ways:

  • A named function, e.g.is.character.

  • An anonymous function, e.g.⁠\(x) all(x < 0)⁠ orfunction(x) all(x < 0).

  • A formula, e.g.~ all(.x < 0). Use.x to refer to the first argument.No longer recommended.

Value

A new predicate function.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),partial(),possibly(),quietly(),safely(),slowly()

Examples

x <- list(x = 1:10, y = rbernoulli(10), z = letters)x |> keep(is.numeric) |> names()x |> keep(negate(is.numeric)) |> names()# Same asx |> discard(is.numeric)

Partially apply a function, filling in some arguments

Description

Partial function application allows you to modify a function by pre-fillingsome of the arguments. It is particularly useful in conjunction withfunctionals and other function operators.

Usage

partial(.f, ...)

Arguments

.f

a function. For the output source to read well, this should be anamed function.

...

named arguments to.f that should be partially applied.

Pass an empty⁠... = ⁠ argument to specify the position of futurearguments relative to partialised ones. Seerlang::call_modify() to learn more about this syntax.

These dots support quasiquotation. If you unquote a value, it isevaluated only once at function creation time. Otherwise, it isevaluated each time the function is called.

Details

partial() creates a function that takes... arguments. Unlikecompose() and other function operators likenegate(), itdoesn't reuse the function signature of.f. This is becausepartial() explicitly supports NSE functions that usesubstitute() on their arguments. The only way to support those isto forward arguments through dots.

Other unsupported patterns:

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),negate(),possibly(),quietly(),safely(),slowly()

Examples

# Partial is designed to replace the use of anonymous functions for# filling in function arguments. Instead of:compact1 <- function(x) discard(x, is.null)# we can write:compact2 <- partial(discard, .p = is.null)# partial() works fine with functions that do non-standard# evaluationmy_long_variable <- 1:10plot2 <- partial(plot, my_long_variable)plot2()plot2(runif(10), type = "l")# Note that you currently can't partialise arguments multiple times:my_mean <- partial(mean, na.rm = TRUE)my_mean <- partial(my_mean, na.rm = FALSE)try(my_mean(1:10))# The evaluation of arguments normally occurs "lazily". Concretely,# this means that arguments are repeatedly evaluated across invocations:f <- partial(runif, n = rpois(1, 5))ff()f()# You can unquote an argument to fix it to a particular value.# Unquoted arguments are evaluated only once when the function is created:f <- partial(runif, n = !!rpois(1, 5))ff()f()# By default, partialised arguments are passed before new ones:my_list <- partial(list, 1, 2)my_list("foo")# Control the position of these arguments by passing an empty# `... = ` argument:my_list <- partial(list, 1, ... = , 2)my_list("foo")

Safely get or set an element deep within a nested data structure

Description

pluck() implements a generalised form of[[ that allow you to indexdeeply and flexibly into data structures. (If you're looking for anequivalent of[, seekeep_at().)pluck() always succeeds, returning.default if the index you are trying to access does not exist or isNULL.(If you're looking for a variant that errors, trychuck().)

⁠pluck<-()⁠ is the assignment equivalent, allowing you to modify an objectdeep within a nested data structure.

pluck_exists() tells you whether or not an object exists using thesame rules as pluck (i.e. aNULL element is equivalent to an absentelement).

Usage

pluck(.x, ..., .default = NULL)pluck(.x, ...) <- valuepluck_exists(.x, ...)

Arguments

.x,x

A vector or environment

...

A list of accessors for indexing into the object. Can bean positive integer, a negative integer (to index from the right),a string (to index into names), or an accessor function(except for the assignment variants which only support names andpositions). If the object being indexed is an S4 object,accessing it by name will return the corresponding slot.

Dynamic dots are supported. In particular, ifyour accessors are stored in a list, you can splice that in with⁠!!!⁠.

.default

Value to use if target isNULL or absent.

value

A value to replace in.x at the pluck location.Usezap() to instead remove the element.

Details

See Also

Examples

# Let's create a list of data structures:obj1 <- list("a", list(1, elt = "foo"))obj2 <- list("b", list(2, elt = "bar"))x <- list(obj1, obj2)# pluck() provides a way of retrieving objects from such data# structures using a combination of numeric positions, vector or# list names, and accessor functions.# Numeric positions index into the list by position, just like `[[`:pluck(x, 1)# same as x[[1]]# Index from the backpluck(x, -1)# same as x[[2]]pluck(x, 1, 2)# same as x[[1]][[2]]# Supply names to index into named vectors:pluck(x, 1, 2, "elt")# same as x[[1]][[2]][["elt"]]# By default, pluck() consistently returns `NULL` when an element# does not exist:pluck(x, 10)try(x[[10]])# You can also supply a default value for non-existing elements:pluck(x, 10, .default = NA)# The map() functions use pluck() by default to retrieve multiple# values from a list:map_chr(x, 1)map_int(x, c(2, 1))# pluck() also supports accessor functions:my_element <- function(x) x[[2]]$eltpluck(x, 1, my_element)pluck(x, 2, my_element)# Even for this simple data structure, this is more readable than# the alternative form because it requires you to read both from# right-to-left and from left-to-right in different parts of the# expression:my_element(x[[1]])# If you have a list of accessors, you can splice those in with `!!!`:idx <- list(1, my_element)pluck(x, !!!idx)

Compute the depth of a vector

Description

The depth of a vector is how many levels that you can index/pluck into it.pluck_depth() was previously calledvec_depth().

Usage

pluck_depth(x, is_node = NULL)

Arguments

x

A vector

is_node

Optionally override the default criteria for determine anelement can be recursed within. The default matches the behaviour ofpluck() which can recurse into lists and expressions.

Value

An integer.

Examples

x <- list(  list(),  list(list()),  list(list(list(1))))pluck_depth(x)x |> map_int(pluck_depth)

Map over multiple input simultaneously (in "parallel")

Description

These functions are variants ofmap() that iterate over multiple argumentssimultaneously. They are parallel in the sense that each input is processedin parallel with the others, not in the sense of multicore computing, i.e.they share the same notion of "parallel" asbase::pmax() andbase::pmin().

Usage

pmap(.l, .f, ..., .progress = FALSE)pmap_lgl(.l, .f, ..., .progress = FALSE)pmap_int(.l, .f, ..., .progress = FALSE)pmap_dbl(.l, .f, ..., .progress = FALSE)pmap_chr(.l, .f, ..., .progress = FALSE)pmap_vec(.l, .f, ..., .ptype = NULL, .progress = FALSE)pwalk(.l, .f, ..., .progress = FALSE)

Arguments

.l

A list of vectors. The length of.l determines the number ofarguments that.f will be called with. Arguments will be supply byposition if unnamed, and by name if named.

Vectors of length 1 will be recycled to any length; all other elementsmust be have the same length.

A data frame is an important special case of.l. It will cause.fto be called once for each row.

.f

A function, specified in one of the following ways:

  • A named function.

  • An anonymous function, e.g.⁠\(x, y, z) x + y / z⁠ orfunction(x, y, z) x + y / z

  • A formula, e.g.~ ..1 + ..2 / ..3. No longer recommended.

[Experimental]

Wrap a function within_parallel() to declare that it should be performedin parallel. Seein_parallel() for more details.Use of... is not permitted in this context.

...

Additional arguments passed on to the mapped function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> map(f, 1, 2, collapse = ",")# do:x |> map(\(x) f(x, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.progress

Whether to show a progress bar. UseTRUE to turn ona basic progress bar, use a string to give it a name, or seeprogress_bars for more details.

.ptype

IfNULL, the default, the output type is the common typeof the elements of the result. Otherwise, supply a "prototype" givingthe desired type of output.

Value

The output length is determined by the maximum length of all elements of.l.The output names are determined by the names of the first element of.l.The output type is determined by the suffix:

Any errors thrown by.f will be wrapped in an error with classpurrr_error_indexed.

See Also

Other map variants:imap(),lmap(),map(),map2(),map_depth(),map_if(),modify()

Examples

x <- list(1, 1, 1)y <- list(10, 20, 30)z <- list(100, 200, 300)pmap(list(x, y, z), sum)# Matching arguments by positionpmap(list(x, y, z), function(first, second, third) (first + third) * second)# Matching arguments by namel <- list(a = x, b = y, c = z)pmap(l, function(c, b, a) (a + c) * b)# Vectorizing a function over multiple argumentsdf <- data.frame(  x = c("apple", "banana", "cherry"),  pattern = c("p", "n", "h"),  replacement = c("P", "N", "H"),  stringsAsFactors = FALSE  )pmap(df, gsub)pmap_chr(df, gsub)# Use `...` to absorb unused components of input list .ldf <- data.frame(  x = 1:3,  y = 10:12,  z = letters[1:3])plus <- function(x, y) x + y## Not run: # this won't workpmap(df, plus)## End(Not run)# but this willplus2 <- function(x, y, ...) x + ypmap_dbl(df, plus2)# The "p" for "parallel" in pmap() is the same as in base::pmin()# and base::pmax()df <- data.frame(  x = c(1, 2, 5),  y = c(5, 4, 8))# all produce the same resultpmin(df$x, df$y)map2_dbl(df$x, df$y, min)pmap_dbl(df, min)

Wrap a function to return a value instead of an error

Description

Create a modified version of.f that return a default value (otherwise)whenever an error occurs.

Usage

possibly(.f, otherwise = NULL, quiet = TRUE)

Arguments

.f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

otherwise

Default value to use when an error occurs.

quiet

Hide errors (TRUE, the default), or display themas they occur?

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),negate(),partial(),quietly(),safely(),slowly()

Examples

# To replace errors with a default value, use possibly().list("a", 10, 100) |>  map_dbl(possibly(log, NA_real_))# The default, NULL, will be discarded with `list_c()`list("a", 10, 100) |>  map(possibly(log)) |>  list_c()

Prepend a vector

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because it's not related to thecore purpose of purrr.

This is a companion toappend() to help merging twolists or atomic vectors.prepend() is a clearer semanticsignal thanc() that a vector is to be merged at the beginning ofanother, especially in a pipe chain.

Usage

prepend(x, values, before = NULL)

Arguments

x

the vector to be modified.

values

to be included in the modified vector.

before

a subscript, before which the values are to be appended. IfNULL, values will be appended at the beginning even forx of length 0.

Value

A merged vector.

Examples

x <- as.list(1:3)x |> append("a")x |> prepend("a")x |> prepend(list("a", "b"), before = 3)prepend(list(), x)

Progress bars in purrr

Description

purrr's map functions have a.progress argument that you can use tocreate a progress bar..progress can be:

It's good practice to name your progress bars, to make it clear whatcalculation or process they belong to. We recommend keeping the namesunder 20 characters, so the whole progress bar fits comfortably even onon narrower displays.

Progress bar parameters

Further documentation

purrr's progress bars are powered by cli, so seeIntroduction to progress bars in cliandAdvanced cli progress barsfor more details.


Indexed errors (purrr_error_indexed)

Description

Thepurrr_error_indexed class is thrown bymap(),map2(),pmap(), and friends.It wraps errors thrown during the processing on individual elements with information about the location of the error.

Structure

purrr_error_indexed has three important fields:

Let's see this in action by capturing the generated condition from a very simple example:

f <- function(x) {  rlang::abort("This is an error")} cnd <- rlang::catch_cnd(map(c(1, 4, 2), f))class(cnd)#> [1] "purrr_error_indexed" "rlang_error"         "error"              #> [4] "condition"cnd$location#> [1] 1cnd$name#> NULLprint(cnd$parent, backtrace = FALSE)#> <error/rlang_error>#> Error in `.f()`:#> ! This is an error

If the input vector is named,name will be non-NULL:

cnd <- rlang::catch_cnd(map(c(a = 1, b = 4, c = 2), f))cnd$name#> [1] "a"

Handling errors

(This section assumes that you're familiar with the basics of error handling in R, as described inAdvanced R.)

This error chaining is really useful when doing interactive data analysis, but it adds some extra complexity when handling errors withtryCatch() orwithCallingHandlers().Let's see what happens by adding a custom class to the error thrown byf():

f <- function(x) {  rlang::abort("This is an error", class = "my_error")} map(c(1, 4, 2, 5, 3), f)#> Error in `map()`:#> i In index: 1.#> Caused by error in `.f()`:#> ! This is an error

This doesn't change the visual display, but you might be surprised if you try to catch this error withtryCatch() orwithCallingHandlers():

tryCatch(  map(c(1, 4, 2, 5, 3), f),  my_error = function(err) {    # use NULL value if error    NULL  })#> Error in `map()`:#> i In index: 1.#> Caused by error in `.f()`:#> ! This is an errorwithCallingHandlers(  map(c(1, 4, 2, 5, 3), f),  my_error = function(err) {    # throw a more informative error    abort("Wrapped error", parent = err)  })#> Error in `map()`:#> i In index: 1.#> Caused by error in `.f()`:#> ! This is an error

That's because, as described above, the error thatmap() throws will always have classpurrr_error_indexed:

tryCatch(  map(c(1, 4, 2, 5, 3), f),  purrr_error_indexed = function(err) {    print("Hello! I am now called :)")  })#> [1] "Hello! I am now called :)"

In order to handle the error thrown byf(), you'll need to userlang::cnd_inherits() on the parent error:

tryCatch(  map(c(1, 4, 2, 5, 3), f),  purrr_error_indexed = function(err) {    if (rlang::cnd_inherits(err, "my_error")) {      NULL    } else {      rlang::cnd_signal(err)    }  })#> NULLwithCallingHandlers(  map(c(1, 4, 2, 5, 3), f),  purrr_error_indexed = function(err) {    if (rlang::cnd_inherits(err, "my_error")) {      abort("Wrapped error", parent = err)    }  })#> Error:#> ! Wrapped error#> Caused by error in `map()`:#> i In index: 1.#> Caused by error in `.f()`:#> ! This is an error

(ThetryCatch() approach is suboptimal because we're no longer just handling errors, but also rethrowing them.The rethrown errors won't work correctly with (e.g.)recover() andtraceback(), but we don't currently have a better approach.In the future we expect toenhancetry_fetch() to make this easier to do 100% correctly).

Finally, if you just want to get rid of purrr's wrapper error, you can resignal the parent error:

withCallingHandlers(  map(c(1, 4, 2, 5, 3), f),  purrr_error_indexed = function(err) {    rlang::cnd_signal(err$parent)  })#> Error in `.f()`:#> ! This is an error

Because we are resignalling an error, it's important to usewithCallingHandlers() and nottryCatch() in order to preserve the full backtrace context.That wayrecover(),traceback(), and related tools will continue to work correctly.


Wrap a function to capture side-effects

Description

Create a modified version of.f that captures side-effects along withthe return value of the function and returns a list containingtheresult,output,messages andwarnings.

Usage

quietly(.f)

Arguments

.f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),negate(),partial(),possibly(),safely(),slowly()

Examples

f <- function() {  print("Hi!")  message("Hello")  warning("How are ya?")  "Gidday"}f()f_quiet <- quietly(f)str(f_quiet())

Create delaying rate settings

Description

These helpers create rate settings that you can pass toinsistently() andslowly(). You can also use them in your own functions withrate_sleep().

Usage

rate_delay(pause = 1, max_times = Inf)rate_backoff(  pause_base = 1,  pause_cap = 60,  pause_min = 1,  max_times = 3,  jitter = TRUE)is_rate(x)

Arguments

pause

Delay between attempts in seconds.

max_times

Maximum number of requests to attempt.

pause_base,pause_cap

rate_backoff() uses an exponentialback-off so that each request waitspause_base * 2^i seconds,up to a maximum ofpause_cap seconds.

pause_min

Minimum time to wait in the backoff; generallyonly necessary if you need pauses less than one second (which maynot be kind to the server, use with caution!).

jitter

Whether to introduce a random jitter in the waiting time.

x

An object to test.

Examples

# A delay rate waits the same amount of time:rate <- rate_delay(0.02)for (i in 1:3) rate_sleep(rate, quiet = FALSE)# A backoff rate waits exponentially longer each time, with random# jitter by default:rate <- rate_backoff(pause_base = 0.2, pause_min = 0.005)for (i in 1:3) rate_sleep(rate, quiet = FALSE)

Wait for a given time

Description

If the rate's internal counter exceeds the maximum number of timesit is allowed to sleep,rate_sleep() throws an error of classpurrr_error_rate_excess.

Usage

rate_sleep(rate, quiet = TRUE)rate_reset(rate)

Arguments

rate

Arate object determining the waiting time.

quiet

IfFALSE, prints a message displaying how long untilthe next request.

Details

Callrate_reset() to reset the internal rate counter to 0.

See Also

rate_backoff(),insistently()


Generate random sample from a Bernoulli distribution

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because it's not related to thecore purpose of purrr.

Usage

rbernoulli(n, p = 0.5)

Arguments

n

Number of samples

p

Probability of gettingTRUE

Value

A logical vector

Examples

rbernoulli(10)rbernoulli(100, 0.1)

Generate random sample from a discrete uniform distribution

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because it's not related to thecore purpose of purrr.

Usage

rdunif(n, b, a = 1)

Arguments

n

Number of samples to draw.

a,b

Range of the distribution (inclusive).

Examples

table(rdunif(1e3, 10))table(rdunif(1e3, 10, -5))

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

Description

reduce() is an operation that combines the elements of a vectorinto a single value. The combination is driven by.f, a binaryfunction that takes two values and returns a single value: reducingf over1:3 computes the valuef(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

Forreduce(), a 2-argument function. The function will be passedthe accumulated value as the first argument and the "next" value as thesecond argument.

Forreduce2(), a 3-argument function. The function will be passed theaccumulated value as the first argument, the next value of.x as thesecond argument, and the next value of.y as the third argument.

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

...

Additional arguments passed on to the reduce function.

We now generally recommend against using... to pass additional(constant) arguments to.f. Instead use a shorthand anonymous function:

# Instead ofx |> reduce(f, 1, 2, collapse = ",")# do:x |> reduce(\(x, y) f(x, y, 1, 2, collapse = ","))

This makes it easier to understand which arguments belong to whichfunction and will tend to yield better error messages.

.init

If supplied, will be used as the first value to startthe accumulation, rather than using.x[[1]]. This is useful ifyou want to ensure thatreduce returns a correct value when.xis 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 aboutdirection below.

.y

Forreduce2() an additionalargument that is passed to.f. Ifinit is not set,.yshould be 1 element shorter than.x.

Direction

When.f is an associative operation like+ orc(), thedirection of reduction does not matter. For instance, reducing thevector1:3 with the binary function+ computes the sum((1 + 2) + 3) from the left, and the same sum(1 + (2 + 3)) from theright.

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

See Also

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

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)

Objects exported from other packages

Description

These objects are imported from other packages. Follow the linksbelow to see their documentation.

rlang

%||%,done,exec,is_atomic,is_bare_atomic,is_bare_character,is_bare_double,is_bare_integer,is_bare_list,is_bare_logical,is_bare_numeric,is_bare_vector,is_character,is_double,is_empty,is_formula,is_function,is_integer,is_list,is_logical,is_null,is_scalar_atomic,is_scalar_character,is_scalar_double,is_scalar_integer,is_scalar_list,is_scalar_logical,is_scalar_vector,is_vector,rep_along,set_names,zap


Re-run expressions multiple times

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because we believe that NSEfunctions are not a good fit for purrr. Also,rerun(n, x) can just aseasily be expressed as⁠map(1:n, \(i) x)⁠

rerun() is a convenient way of generating sample data. It works similarly toreplicate(..., simplify = FALSE).

Usage

rerun(.n, ...)

Arguments

.n

Number of times to run expressions

...

Expressions to re-run.

Value

A list of length.n. Each element of... will bere-run once for each.n.

There is one special case: if there's a single unnamed input, the secondlevel list will be dropped. In this case,rerun(n, x) behaves likereplicate(n, x, simplify = FALSE).

Examples

# old5 |> rerun(rnorm(5)) |> str()# new1:5 |> map(\(i) rnorm(5)) |> str()# old5 |>  rerun(x = rnorm(5), y = rnorm(5)) |>  map_dbl(\(l) cor(l$x, l$y))# new1:5 |>  map(\(i) list(x = rnorm(5), y = rnorm(5))) |>  map_dbl(\(l) cor(l$x, l$y))

Wrap a function to capture errors

Description

Creates a modified version of.f that always succeeds. It returns a listwith componentsresult anderror. If the function succeeds,resultcontains the returned value anderror isNULL. If an error occurred,error is anerror object andresult is eitherNULL orotherwise.

Usage

safely(.f, otherwise = NULL, quiet = TRUE)

Arguments

.f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

otherwise

Default value to use when an error occurs.

quiet

Hide errors (TRUE, the default), or display themas they occur?

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),negate(),partial(),possibly(),quietly(),slowly()

Examples

safe_log <- safely(log)safe_log(10)safe_log("a")list("a", 10, 100) |>  map(safe_log) |>  transpose()# This is a bit easier to work with if you supply a default value# of the same type and use the simplify argument to transpose():safe_log <- safely(log, otherwise = NA_real_)list("a", 10, 100) |>  map(safe_log) |>  transpose() |>  simplify_all()

Wrap a function to wait between executions

Description

slowly() takes a function and modifies it to wait a givenamount of time between each call.

Usage

slowly(f, rate = rate_delay(), quiet = TRUE)

Arguments

f

A function to modify, specified in one of the following ways:

  • A named function, e.g.mean.

  • An anonymous function, e.g.⁠\(x) x + 1⁠ orfunction(x) x + 1.

  • A formula, e.g.~ .x + 1. No longer recommended.

rate

Arate object. Defaults to a constant delay.

quiet

Hide errors (TRUE, the default), or display themas they occur?

Value

A function that takes the same arguments as.f, but returnsa different value, as described above.

Adverbs

This function is called an adverb because it modifies the effect of afunction (a verb). If you'd like to include a function created an adverbin a package, be sure to readfaq-adverbs-export.

See Also

Other adverbs:auto_browse(),compose(),insistently(),negate(),partial(),possibly(),quietly(),safely()

Examples

# For these example, we first create a custom rate# with a low waiting time between attempts:rate <- rate_delay(0.1)# slowly() causes a function to sleep for a given time between calls:slow_runif <- slowly(\(x) runif(1), rate = rate, quiet = FALSE)out <- map(1:5, slow_runif)

Splice objects and lists of objects into a list

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because we no longer believe thatthis style of implicit/automatic splicing is a good idea; instead userlang::list2() +⁠!!!⁠ orlist_flatten().

splice() splices all arguments into a list. Non-list objects and listswith a S3 class are encapsulated in a list before concatenation.

Usage

splice(...)

Arguments

...

Objects to concatenate.

Value

A list.

Examples

inputs <- list(arg1 = "a", arg2 = "b")# splice() concatenates the elements of inputs with arg3splice(inputs, arg3 = c("c1", "c2")) |> str()list(inputs, arg3 = c("c1", "c2")) |> str()c(inputs, arg3 = c("c1", "c2")) |> str()

Transpose a list.

Description

[Superseded]

transpose() turns a list-of-lists "inside-out"; it turns a pair of listsinto a list of pairs, or a list of pairs into pair of lists. For example,if you had a list of length n where each component had valuesa andb,transpose() would make a list with elementsa andb that contained lists of length n. It's called transpose becausex[[1]][[2]] is equivalent totranspose(x)[[2]][[1]].

This function was superseded in purrr 1.0.0 becauselist_transpose()has a better name and can automatically simplify the output, as is commonlyneeded. Superseded functions will not go away, but will only receive criticalbug fixes.

Usage

transpose(.l, .names = NULL)

Arguments

.l

A list of vectors to transpose. The first element is used as thetemplate; you'll get a warning if a subsequent element has a differentlength.

.names

For efficiency,transpose() bases the return structure onthe first component of.l by default. Specify.names to override this.

Value

A list with indexing transposed compared to.l.

transpose() is its own inverse, much like the transpose operation on amatrix. You can get back the original input by transposing it twice.

Examples

x <- map(1:5, \(i) list(x = runif(1), y = runif(5)))# wasx |> transpose() |> str()# nowx |> list_transpose(simplify = FALSE) |> str()# transpose() is useful in conjunction with safely() & quietly()x <- list("a", 1, 2)y <- x |> map(safely(log))# wasy |> transpose() |> str()# now:y |> list_transpose() |> str()# Previously, output simplification required a call to another functionx <- list(list(a = 1, b = 2), list(a = 3, b = 4), list(a = 5, b = 6))x |> transpose() |> simplify_all()# Now can take advantage of automatic simplificationx |> list_transpose()# Provide explicit component names to prevent loss of those that don't# appear in first componentll <- list(  list(x = 1, y = "one"),  list(z = "deux", x = 2))ll |> transpose()nms <- ll |> map(names) |> reduce(union)# wasll |> transpose(.names = nms)# nowll |> list_transpose(template = nms)# and can supply default valuell |> list_transpose(template = nms, default = NA)

Update a list with formulas

Description

[Deprecated]

update_list() was deprecated in purrr 1.0.0, because we no longer believethat functions that use NSE are a good fit for purrr.

update_list() handles formulas and quosures that can refer tovalues existing within the input list. This function is deprecatedbecause we no longer believe that functions that use tidy evaluation area good fit for purrr.

Usage

update_list(.x, ...)

Arguments

.x

List to modify.

...

New values of a list. Usezap() to remove values.

These values should be either all named or all unnamed. Wheninputs are all named, they are matched to.x by name. When theyare all unnamed, they are matched by position.

Dynamic dots are supported. In particular, if yourreplacement values are stored in a list, you can splice that in with⁠!!!⁠.


Match/validate a set of conditions for an object and continue with the actionassociated with the first valid match.

Description

[Deprecated]

This function was deprecated in purrr 1.0.0 because it's not related to thecore purpose of purrr. You can pull your code out of a pipe and use regularif/⁠else⁠ statements instead.

when() is a flavour of pattern matching (or an if-else abstraction) inwhich a value is matched against a sequence of condition-action sets. When avalid match/condition is found the action is executed and the result of theaction is returned.

Usage

when(., ...)

Arguments

.

the value to match against

...

formulas; each containing a condition as LHS and an action as RHS.named arguments will define additional values.

Value

The value resulting from the action of the first validmatch/condition is returned. If no matches are found, and no default isgiven, NULL will be returned.

Validity of the conditions are tested withisTRUE, or equivalentlywithidentical(condition, TRUE).In other words conditions resulting in more than one logical will neverbe valid. Note that the input value is always treated as a single object,as opposed to theifelse function.

Examples

1:10 |>  when(    sum(.) <=  50 ~ sum(.),    sum(.) <= 100 ~ sum(.)/2,    ~ 0  )# nowx <- 1:10if (sum(x) < 10) {  sum(x)} else if (sum(x) < 100) {  sum(x) / 2} else {  0}

[8]ページ先頭

©2009-2025 Movatter.jp