Skip to contents

as_loop() takes a function call to one of {purrr}'s iterator functions, such as purrr::map(), and translates it into a regular for loop. Depending on the output context, the translation is either (i) printed to the console, (ii) copied to the clipboard or (iii) directly inserted into RStudio. Note that the latter two options require the {clipr} respectively the {rstudioapi} package to be installed.

The usage is pretty straight-forward: Just wrap a call to a {purrr} iterator function into as_loop() or us one of the pipe operators (|> or %>%) to pipe the function call into as_loop(). For details see the examples below.

Usage

as_loop(
  .expr,
  simplify = TRUE,
  output_nm = "out",
  idx = "i",
  output_context = default_context(),
  return = c("string", "eval")
)

Arguments

.expr

A function call to a {purrr} iterator function. See the "Supported functions" section below for an overview of which {purrr} iterator functions are currently supported.

simplify

When TRUE, the default, as_loop() will run the function call in .expr to check two things: (1) Whether the call is valid. If not, an error will be thrown, pointing out that the underlying function call is invalid. (2) Whether the resulting return value contains NULL. In this case the for loop needs to be more verbose. When simplify is set FALSE the function call in .expr is not checked for errors and the resulting for loop will be more verbose even if NULL is not among the return values. It is recommended to set simplify to FALSE for calculation-heavy function calls.

output_nm

sets the name of the resulting output object. The default name is out.

idx

sets the name of the index of the for loop. The default index is i.

output_context

An optional output context that defines the output target. Possible values are one or several of:

  • "rstudio": This will insert the translation to the location where as_loop() was run. If it was run from within an R script, the for loop will be inserted there, otherwise in the console. Note that the {rstudioapi} package is required for this option.

  • "clipboard": This will copy the for loop translation to the clipboard. Note that the {clipr} package is required for this option.

  • "console": This will print the call to the console using cat().

The default setting is to call default_context(). This function first looks at the "loopurrr.output" option. If the option is not specified, then it will default to c("rstudio", "clipboard", "console"). In this case as_loop() will run the output options from left to right (starting with "rstudio") until successful. If neither the rstudioapi package nor the clipr package are installed, the output context will fall back to "console".

return

When set to "string", the default, as_loop() will return the translated code as character strings to the location specified in output_context. When set to "eval", the translated code will be evaluated in a dedicated environment and the output object will be returned. This option is especially for testing whether as_loop() works as expected. It should be irrelevant for most users.

Value

Depending on the return argument the return value is:

  1. When output = "string": NULL. As a side-effect, the translated for loop will be returned to the specified output context.

  2. When output = "eval": Usually the return value of the output object that is constructed with the for loop. In case of a call to walk, walk2 etc. the (first) input object will be returned.

Supported functions

The following iterator functions from the {purrr} package are currently supported:

options(width = 60)
get_supported_fns("as_loop")
#> $map
#>  [1] "map"     "map_at"  "map_chr" "map_dbl" "map_df" 
#>  [6] "map_dfc" "map_dfr" "map_if"  "map_int" "map_lgl"
#> [11] "map_raw"
#> 
#> $imap
#> [1] "imap"     "imap_chr" "imap_dbl" "imap_dfc" "imap_dfr"
#> [6] "imap_int" "imap_lgl" "imap_raw"
#> 
#> $map
#> [1] "map2"     "map2_chr" "map2_dbl" "map2_df"  "map2_dfc"
#> [6] "map2_dfr" "map2_int" "map2_lgl" "map2_raw"
#> 
#> $pmap
#> [1] "pmap"     "pmap_chr" "pmap_dbl" "pmap_df"  "pmap_dfc"
#> [6] "pmap_dfr" "pmap_int" "pmap_lgl" "pmap_raw"
#> 
#> $lmap
#> [1] "lmap"    "lmap_at"
#> 
#> $modify
#> [1] "modify"    "modify_at" "modify_if" "modify2"  
#> [5] "imodify"  
#> 
#> $walk
#> [1] "iwalk" "pwalk" "walk"  "walk2"
#> 
#> $accumulate
#> [1] "accumulate"  "accumulate2"
#> 
#> $reduce
#> [1] "reduce"  "reduce2"

Examples

If we wrap or pipe a call to purrr::map() into as_loop() it will be translated into a regular for loop. Depending on the output context, the resulting for loop will either be (i) inserted directly into a script in RStudio, (ii) copied to the clipboard or (iii) printed to the console.

x <- list(1, c(1:2), c(1:3))
as_loop(map(x, sum))        # wrap a call in `as_loop()`
map(x, sum) %>% as_loop() # pipe a call into `as_loop()`

# --- convert: `map(x, sum)` as loop --- #
out <- vector("list", length = length(x))

for (i in seq_along(x)) {
  out[[i]] <- sum(x[[i]])
}
# --- end loop --- #

The output_nm argument lets us specify the name of the resulting output object. In the example below ".res". The idx argument lets us specify the index to be used. In the example below "j".

x <- list(1, c(1:2), c(1:3))
map_dbl(x, sum) %>%
  as_loop(., output_nm = ".res", idx = "j")

# --- convert: `map_dbl(x, sum)` as loop --- #
.res <- vector("double", length = length(x))

for (j in seq_along(x)) {
  .res[[j]] <- sum(x[[j]])
}
# --- end loop --- #

When simplify is set FALSE as_loop will neither check the validity of the underlying call nor the expected output. In this case the resulting for loop is more verbose. This is because we need to take the case of NULL in the return values into account. In the example below we further see what happens, when we use an unnamed object, such as 1:3, in the call to purrr::map(). as_loop() assign unnamed objects an internal name. In the example below .inp1.

map(1:3, sum) %>% as_loop(., simplify = FALSE)

# --- convert: `map(1:3, sum)` as loop --- #
.inp1 <- 1:3
out <- vector("list", length = length(.inp1))

for (i in seq_along(.inp1)) {
  .tmp <- sum(.inp1[[i]])
  if (!is.null(.tmp))
    out[[i]] <- .tmp
}
# --- end loop --- #