Ratnanil
Ratnanil

Reputation: 1752

Counter in purrr's map* function family

I often need some sort of counter / index value when applying loop-functions to vectors / list. When using basic loop functions, this index can be created by successively adding 1 to some initial value. Consider the following example:

lets <- letters[1:5]

n = 0
for (le in lets){
  n = n+1
  print(paste(le,"has index",n))
}
#> [1] "a has index 1"
#> [1] "b has index 2"
#> [1] "c has index 3"
#> [1] "d has index 4"
#> [1] "e has index 5"

The only way I've been able to access such an index value with the loop-functions from the purrr package is using map2. Is there a more elegant way to do this using only purrr::map()?

library(purrr)


map2(lets,1:length(lets),~paste(.x,"has index",.y))

#> [[1]]
#> [1] "a has index 1"
#> 
#> [[2]]
#> [1] "b has index 2"
#> 
#> [[3]]
#> [1] "c has index 3"
#> 
#> [[4]]
#> [1] "d has index 4"
#> 
#> [[5]]
#> [1] "e has index 5"

Upvotes: 8

Views: 1889

Answers (2)

markus
markus

Reputation: 26343

Try imap

lets <- letters[1:5]
purrr::imap(lets, ~paste(.x,"has index",.y))
#[[1]]
#[1] "a has index 1"

#[[2]]
#[1] "b has index 2"

#[[3]]
#[1] "c has index 3"

#[[4]]
#[1] "d has index 4"

#[[5]]
#[1] "e has index 5"

Note that imap will use the names of the elements of .x as .y argument if the elements are named. If you don't want that use imap(unname(...), ...) - thanks to @Moody_Mudskipper.


A base R approach could be

sprintf("%s has index %d", lets, seq_along(lets))
# [1] "a has index 1" "b has index 2" "c has index 3" "d has index 4" "e has index 5"

Upvotes: 4

A. Stam
A. Stam

Reputation: 2222

The closest approximation of what you're looking for is purrr::imap, which is described in the documentation as

short hand for map2(x, names(x), ...) if x has names, or map2(x, seq_along(x), ...) if it does not.

The following code works:

lets <- letters[1:5]

purrr::imap(lets, ~print(paste(.x, "has index", .y)))

I'm assuming you are in fact trying to create a new object and store it in a new variable. If you are looking to show output (like in this example, where the result is a print to the console), you should use the equivalent function iwalk which returns its output invisibly.

Upvotes: 6

Related Questions