How to mutate a list-column that holds functions by converting strings to functions with the same name that are available in the environment?
I'm building a tibble in which I organize names (as chr
) of data objects and the relevant wrangling function for each one.
For example, I have one function for wrangling mtcars
and one function for wrangling iris
:
library(dplyr)
wrangle_mtcars <- function() {
mtcars %>%
group_by(am) %>%
summarise(mean_mpg = mean(mpg))
}
wrangle_iris <- function() {
iris %>%
group_by(Species) %>%
summarise(across(starts_with("Sepal"), mean))
}
And I want to organize them in a table that looks like that:
library(tibble)
my_trb <-
tribble(~data_name, ~.fn_wrangling,
"mtcars", wrangle_mtcars,
"iris", wrangle_iris)
my_trb
#> # A tibble: 2 x 2
#> data_name .fn_wrangling
#> <chr> <list>
#> 1 mtcars <fn>
#> 2 iris <fn>
But instead of building my_trb
manually as I did above, I want to do it programmatically. That is, if I'm already given a 1-column table with the name of the data object, I want to simply paste a "wrangle_"
prefix and have the tibble "understand" that I'm referring to the function with the same name that is in the global environment.
In other words I want to get from:
given_table <- tibble(data_name = c("mtcars", "iris"))
to
## # A tibble: 2 x 2
## data_name .fn_wrangling
## <chr> <list>
## 1 mtcars <fn>
## 2 iris <fn>
By doing something like:
given_table %>%
mutate(.fn_wrangling = list(paste0("wrangle_", data_name) %>% as.name))
## # A tibble: 2 x 2
## data_name .fn_wrangling
## <chr> <list>
## 1 mtcars <sym> # <----| but I want it to be <fn> as in `my_trb`, not <sym>
## 2 iris <sym> # <----|
But if I use as.function()
instead of as.name()
it throws an error:
given_table %>%
mutate(.fn_wrangling = list(paste0("wrangle_", data_name) %>% as.function))
Error: Problem with
mutate()
column.fn_wrangling
.
i.fn_wrangling = list(paste0("wrangle_", data_name) %>% as.function)
.
x list argument expected
Solution 1:
We could use match.fun
library(dplyr)
given_table %>%
rowwise %>%
mutate(.fn_wrangling = list(match.fun(paste0("wrangle_", data_name)))) %>%
ungroup
# A tibble: 2 × 2
data_name .fn_wrangling
<chr> <list>
1 mtcars <fn>
2 iris <fn>