assigning id values from values, not names, with purrr::map_dfr

Viewed 346

I think this question is related to Using map_dfr and .id for list names and list of list names but not identical ...

I often use map_dfr for a case where I want to use the value of each argument, not its name, as the .id variable. Here's a silly example: I am computing the mean of mtcars$mpg raised to the second, fourth, and sixth power:

library(tidyverse)
list(2,4,6) %>% map_dfr(~tibble(x=mean(mtcars$mpg^.)), .id="name")
##   name           x
##   <chr>      <dbl>
## 1 1           439.
## 2 2        262350.
## 3 3     198039783.

I would like the name variable to be 2, 4, 6 instead of 1, 2, 3. I can hack this by including setNames(.data) in the pipeline:

list(2,4,6) %>% 
   setNames(.data) %>% 
   map_dfr(~tibble(x=mean(mtcars$mpg^.)), .id="name")

but I wonder if there is a more idiomatic approach I'm missing?


As for the suggestion of using something like ~ tible(name=., ...): nice, but slightly less convenient for the case where the mapping function already returns a tibble, because we have to add an otherwise unnecessary tibble() call:

list(2, 4, 6) %>%   
    map_dfr(~ tibble(name=., 
       broom::tidy(lm(mpg~cyl, data=mtcars, offset=rep(., nrow(mtcars))))))
3 Answers

OK, I think I found this shortly before posting (so I'll answer). This answer points out that tibble::lst() is a self-naming list function, so as long as we use tibble::lst(2,4,6) instead of list(2,4,6), it Just Works, e.g.

lst(2,4,6) %>% map_dfr(~tibble(x=mean(mtcars$mpg^.)), .id="name")

This can work too:

library(tidyverse)

#@ben Bolker answer.
lst(2,4,6) %>% map_dfr(~tibble(x=mean(mtcars$mpg^.)), .id="power")
#> # A tibble: 3 x 2
#>   power          x
#>   <chr>      <dbl>
#> 1 2           439.
#> 2 4        262350.
#> 3 6     198039783.

list(2, 4, 6) %>% map_df(~ tibble(power = as.character(.x) , x = mean(mtcars$mpg^.)))
#> # A tibble: 3 x 2
#>   power          x
#>   <chr>      <dbl>
#> 1 2           439.
#> 2 4        262350.
#> 3 6     198039783.

#another option
seq(2, 6, 2) %>%  map2_df(rerun(length(.), mtcars$mpg), ~ c(x = as.character(.x), mean = round(mean(.y^.x), 0)))
#> # A tibble: 3 x 2
#>   x     mean     
#>   <chr> <chr>    
#> 1 2     439      
#> 2 4     262350   
#> 3 6     198039783

Created on 2021-06-06 by the reprex package (v2.0.0)

This is also possible, however it would not have been my first choice and only a map would suffice:

library(purrr)

list(2, 4, 6) %>%
  pmap_dfr(~ tibble(power = c(...), x = map_dbl(c(...), ~ mean(mtcars$mpg ^ .x))))

# A tibble: 3 x 2
  power          x
  <dbl>      <dbl>
1     2       439.
2     4    262350.
3     6 198039783.
Related