purrr enhances R’s functional programming (FP) toolkit by providing a complete and consistent set of tools for working with functions and vectors.
If you’ve never heard of FP before, the best place to start is the family of map() functions which allow you to replace many for loops with code that is both more succinct and easier to read.
The best place to learn about the map() functions is the iterationchapter in R for Data Science.
library(purrr)Map Functions#
x <- list(a = 1:10, b = 11:20, c = 21:30)
y <- list(1, 2, 3)
z <- list(4, 5, 6)
l1 <- list(x = c("a", "b"), y = c("c", "d"))
l2 <- list(x = "a", y = "z")-
map(.x, .f, ...): Apply a function to each element of a list of vector, and return a list.map(l1, sort, decreasing = TRUE) -
map2(.x, .y, .f, ...): Apply a function pairs of elements from two lists or vectors, return a list.map2(x, y, \(x, y ) x*y)imap(.x, .f, ...)is shorthand formap2(.x, names(.x), .f)ormap2(.x, seq_along(.x), .f)depending on whether.xis named or not. -
pmap(.l, .f, ...): Apply a function to groups of elements from a list of lists or vectors, return a list.pmap(list(x, y, z), function(first, second, third) first * (second + third))
| One list | Two lists | Many lists | ||
|---|---|---|---|---|
| Logical | Returns a logical vector. | map_lgl(x, is.integer) |
map2_lgl(l2, l1, `%in%`) |
pmap_lgl(list(l2, l1), `%in%`) |
| Integer | Returns an integer vector. | map_int(x, length) |
map2_int(y, z, `+`) |
pmap_int(list(y, z), `+`) |
| Double | Returns a double vector. | map_dbl(x, mean) |
map2_dbl(y, z, ~ .x / .y) |
pmap_dbl(list(y, z), ~ .x / .y) |
| Character | Returns a character vector. | map_chr(l1, paste, collapse = "") |
map2_chr(l1, l2, paste, collapse = ",", sep = ":") |
pmap_chr(list(l1, l2), paste, collapse = ",", sep = ":") |
| Vector | Returns a vector that is of the simplest common type. | map_vec(l1, paste, collapse = "") |
map2_vec(l1, l2, paste, collapse = ",", sep = ":") |
pmap_chr(list(l1, l2), paste, collapse = ",", sep = ":") |
| No output | Calls .f for its side-effect. |
walk(x, print) |
walk2(objs, paths, save) |
pwalk(list(objs, paths), save) |
Function Shortcuts#
-
Use
\(x)with functions likemap()that have single arguments.map(l, \(x) x + 2)becomesmap(l, function(x) x + 2). -
Use
\(x, y)with functions likemap2()that have two arguments.map2(l, p, \(x, y) x + y)becomesmap2(l, p, function(l, p) l + p). -
Use
\(x, y, z)etc. with functions likepmap()that have many arguments.pmap(list(x, y, z), \(x, y, z) x + y / z)becomespmap(list(x, y, z), function(x, y, z) x * (y + z)). -
Use
\(x, y)with functions likeimap().xwill get the list value andywith get the index, or name if available.imap(list("a", "b", "c"), \(x, y) paste0(y, ": ", x))outputsindex: valuefor each item. -
Use a
stringorintegerwith any map function to index list elements by name or position.map(l, "name")becomesmap(l, function(x) x[["name"]]).
Modify#
-
modify(.x, .f, ...): Apply a function to each element. Alsomodify2()andimodify().modify(x, ~ . + 2) -
modify_at(.x, .at, .f, ...): Apply a function to selected elements. Alsomap_at().modify_at(x, "b", ~ . + 2) -
modify_if(.x, .p, .f, ...): Apply a function to elements that pass a test. Alsomap_if().modify_if(x, is.numeric, ~ . + 2) -
modify_depth(.x, .depth, .f, ...): Apply function to each element at a given level of a list. Alsomap_depth().modify_depth(x, 1, ~ . + 2)
Reduce#
-
reduce(.x, .f, ..., .init, .dir = c("forward", "backward")): Apply function recursively to each element of a list of vector. Alsoreduce2().a <- list(1, 2, 3, 4) reduce(a, sum) -
accumulate(.x, .f, ..., .init): Reduce a list, but also return intermediate results in a list. Alsoaccumulate2().a <- list(1, 2, 3, 4) accumulate(a, sum)
Vectors#
-
compact(.x, .p = identity): Discard empty elements.compact(x) -
keep_at(): Keep/discard elements based by name or position.keep_at(x, "a") keep_at(x, 2) -
set_names(x, nm = x): Set the names of a vector/list directly or with a function.set_names(x, c("p", "q", "r")) set_names(x, tolower)
Predicate functions#
A predicate function returns a single TRUE or FALSE and purrr provides
-
keep(.x, .p, ...)retains elements where the predicate isTRUE;discard(.x, .p, ...)drops elements where the predicate isTRUE.keep(x, is.numeric) discard(x, is.numeric) -
head_while(.x, .p, ...)keeps the first elements until one fails the predicate. Alsotail_while().head_while(x, is.character) -
detect(.x, .f, ..., dir = c("forward", "backward"), .right = NULL): Find first element to pass.detect(x, is.character) -
detect_index(.x, .f, ..., dir = c("forward", "backward"), .right = NULL): Find index of first element to pass.detect_index(x, is.character) -
every(.x, .p, ...): Do all elements pass a test?every(x, is.character) -
some(.x, .p, ...): Do some elements pass a test?some(x, is.character) -
none(.x, .p, ...): Do no elements pass a test?none(x, is.character) -
has_element(.x, .y): Does a list contain an element?has_element(x, "foo")
Pluck#
-
pluck(.x, ..., .deault = NULL): Select an element by name or index. Alsoattr_getter()andchuck().pluck(x, "b") x |> pluck("b") -
assign_in(x, where, value): Assign a value to a location using pluck selection.assign_in(x, "b", 5) x |> assign_in("b", 5) -
modify_in(.x, .where,, .f): Apply a function to a value at a selected location.modify_in(x, "b", abs)
Reshape#
-
list_flatten(x): Remove a level of indexes from a list.list_flatten(x) -
list_transpose(x): Transposes the index order in a multi-level list.list_transpose(x)
Concatenate#
x1 <- list(a = 1, b = 2, c = 3)
x2 <- list(
a = data.frame(x = 1:2),
b = data.frame(y = "a")
)-
list_c(): Combines elements into a vector by concatenating them together.list_c(x1) -
list_rbind(): Combines elements into a data frame by row-binding them together.list_rbind(x2) -
list_cbind(): Combines elements into a data frame by column-binding them together.list_cbind(x2)
List-Columns#
List-columns are columns of a data frame where each element is a list or vector instead of an atomic value. Columns can also be lists of data frames. See tidyr for more about nested data and list columns.
Work With List-Columns#
Manipulate list-columns like any other kind of column, using dplyr functions like mutate() and transmute().
Because each element is a list, use map functions within a column function to manipulate each element.
-
map(),map2(), orpmap()return lists and will create new list-columns. In this example,transmute()is a column function,map2()is a list function which returns a list, andvehiclesandstarshipsare list-columns.dplyr::starwars |> dplyr::mutate(ships = map2(vehicles, starships, append)) -
Suffixed map functions like
map_int()return an atomic data type and will simplify list-columns into regular columns. In this example,mutate()is a column function,map_int()is a list function which returns a column vector, andfilmsis a list column.dplyr::starwars |> dplyr::mutate(n_films = map_int(films, length))
CC BY SA Posit Software, PBC • info@posit.co • posit.co
Learn more at purrr.tidyverse.org.
Updated: 2026-10.
packageVersion("purrr")[1] '1.2.2'

