% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/map-depth.R
\name{map_depth}
\alias{map_depth}
\alias{modify_depth}
\title{Map/modify elements at given depth}
\usage{
map_depth(.x, .depth, .f, ..., .ragged = .depth < 0, .is_node = NULL)

modify_depth(.x, .depth, .f, ..., .ragged = .depth < 0, .is_node = NULL)
}
\arguments{
\item{.x}{A list or atomic vector.}

\item{.depth}{Level of \code{.x} to map on. Use a negative value to
count up from the lowest level of the list.
\itemize{
\item \code{map_depth(x, 0, fun)} is equivalent to \code{fun(x)}.
\item \code{map_depth(x, 1, fun)} is equivalent to \code{x <- map(x, fun)}
\item \code{map_depth(x, 2, fun)} is equivalent to \verb{x <- map(x, \\(y) map(y, fun))}
}}

\item{.f}{A function, specified in one of the following ways:
\itemize{
\item A named function, e.g. \code{mean}.
\item An anonymous function, e.g. \verb{\\(x) x + 1} or \code{function(x) x + 1}.
\item A formula, e.g. \code{~ .x + 1}. Use \code{.x} to refer to the first
argument. No longer recommended.
\item A string, integer, or list, e.g. \code{"idx"}, \code{1}, or \code{list("idx", 1)} which
are shorthand for \verb{\\(x) pluck(x, "idx")}, \verb{\\(x) pluck(x, 1)}, and
\verb{\\(x) pluck(x, "idx", 1)} respectively. Optionally supply \code{.default} to
set a default value if the indexed element is \code{NULL} or does not exist.
}

\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}}

Wrap a function with \code{\link[=in_parallel]{in_parallel()}} to declare that it should be performed
in parallel. See \code{\link[=in_parallel]{in_parallel()}} for more details.
Use of \code{...} is not permitted in this context.}

\item{...}{Additional arguments passed on to the mapped function.

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

\if{html}{\out{<div class="sourceCode R">}}\preformatted{# Instead of
x |> map(f, 1, 2, collapse = ",")
# do:
x |> map(\\(x) f(x, 1, 2, collapse = ","))
}\if{html}{\out{</div>}}

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

\item{.ragged}{If \code{TRUE}, will apply to leaves, even if they're not
at depth \code{.depth}. If \code{FALSE}, will throw an error if there are
no elements at depth \code{.depth}.}

\item{.is_node}{A predicate function that determines whether an element is
a node (by returning \code{TRUE}) or a leaf (by returning \code{FALSE}). The
default value, \code{NULL}, treats simple lists as nodes and everything else
(including richer objects like data frames and linear models) as leaves,
using \code{\link[vctrs:obj_is_list]{vctrs::obj_is_list()}}. To recurse into all objects built on lists
use \code{\link[=is.list]{is.list()}}.}
}
\description{
\code{map_depth()} calls \code{map(.y, .f)} on all \code{.y} at the specified \code{.depth} in
\code{.x}. \code{modify_depth()} calls \code{modify(.y, .f)} on \code{.y} at the specified
\code{.depth} in \code{.x}.
}
\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()
}
\seealso{
\code{\link[=modify_tree]{modify_tree()}} for a recursive version of \code{modify_depth()} that
allows you to apply a function to every leaf or every node.

Other map variants: 
\code{\link{imap}()},
\code{\link{lmap}()},
\code{\link{map}()},
\code{\link{map2}()},
\code{\link{map_if}()},
\code{\link{modify}()},
\code{\link{pmap}()}

Other modify variants: 
\code{\link{modify}()},
\code{\link{modify_tree}()}
}
\concept{map variants}
\concept{modify variants}
