Home > database >  Use exec() with a function that uses summarise with curly-curly
Use exec() with a function that uses summarise with curly-curly

Time:01-16

I'm trying to run this function with exec(). I have a workaround that uses rlang::expr and then !! but that implies changing the function to accept an expression as an argument instead of a quoted variable. Is there a way to call this function without loosing the ability to pass quoted arguments?

library(tidyverse)

calc_mean <- function(df, col) {
  df %>%
    summarise(mean({{ col }}))
}

#doesn't work
map(list('calc_mean'), ~exec(.x, df = mtcars, col = mpg))
#> Warning in mean.default(~structure(list(manufacturer = c("audi", "audi", :
#> argument is not numeric or logical: returning NA
#> [[1]]
#>   mean(...)
#> 1        NA

Created on 2022-01-15 by the reprex package (v2.0.1)

My expected output would be the same as calling the function outside exec:

calc_mean(mtcars, mpg)
#>   mean(mpg)
#> 1  20.09062

CodePudding user response:

I expect you want to loop over a list of function names and this is just a minimal example (otherwise there would be no need for map).

We could use base R do.call, but we'd have to quote the arguments and put them in a list:

library(tidyverse)

calc_mean <- function(df, col) {
  df %>%
    summarise(mean({{ col }}))
}

map(list("calc_mean"), ~ do.call(.x, list(df = quote(mtcars), col = quote(mpg))))
#> [[1]]
#>   mean(mpg)
#> 1  20.09062

Another possible approach is to work with get or mget (if you have a vector of function names) and then we can do something crazy. We just call .x as a function in your lambda function. No list or quote needed. It is best practice to specify the envir argument of get which I skipped in the minimal example below:

map(list(get("calc_mean")), ~ .x(df = mtcars, col = mpg))

#> [[1]]
#>   mean(mpg)
#> 1  20.09062

Created on 2022-01-15 by the reprex package (v0.3.0)

  •  Tags:  
  • Related