Search code examples
rdplyrpurrr

Splicing does not work when `map()` is nested inside of `mutate()`


I am trying to take a column of index vectors and splice them into a pluck() call to get the value at those indexes. It works fine if I do that in a map() call at the top level, but it does not recognize .x argument when the map() is called inside of a mutate(). Can anyone explain why? Is there a syntax I am missing?

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(purrr)

lst <-
    list(a=1, b=list(c=2, d=3))
str(lst)
#> List of 2
#>  $ a: num 1
#>  $ b:List of 2
#>   ..$ c: num 2
#>   ..$ d: num 3

#;; Note what is at index c(2L, 2L)
lst[[c(2L, 2L)]]
#> [1] 3

#;; Put that index in a dataframe column.
idx_df <-
    tibble(idx=list(c(2L, 2L)))
idx_df
#> # A tibble: 1 × 1
#>   idx      
#>   <list>   
#> 1 <int [2]>


#;; This does not work, but I expect it to, as I believe it should work
#;; analagously to what is below.
tryCatch({
    idx_df |>
        mutate(val = map_dbl(idx, ~ pluck(lst, !!!.x)))
}
, error=\(e) e)
#> <simpleError in quos(..., .ignore_empty = "all"): object '.x' not found>


#;; This works, but I should be able to do this in a mutate call.
idx_df$val <-
    map_dbl(idx_df$idx, ~ pluck(lst, !!!.x))
idx_df
#> # A tibble: 1 × 2
#>   idx         val
#>   <list>    <dbl>
#> 1 <int [2]>     3

Created on 2023-05-09 with reprex v2.0.2


Solution

  • As highlighted, problem seems to be when !!! is evaluated. As a simple workaround, you could create an interim function so that !!! isn't evaluated until the function is called:

    library(dplyr)
    library(purrr)
    
    lst <-
      list(a=1, b=list(c=2, d=3))
    
    idx_df <-
      tibble(idx=list(c(2L, 2L)))
    
    pluck_loc <-  function(x) {
      pluck(lst, !!!x)
    }
    
    idx_df |>
      mutate(val = map_dbl(idx, pluck_loc))
    #> # A tibble: 1 × 2
    #>   idx         val
    #>   <list>    <dbl>
    #> 1 <int [2]>     3