rfunctional-programmingpurrrrlang

R question: Use map to convert a list of functions to a list of strings of their function names


If I want to convert the name of a function into a string, I can do this:

deparse(substitute(mean))

which would return: [1] "mean"

What if I want to do this to a list of functions, how do a create a function (e.g. get_function_name_as_string) that convert their names as strings? For example,

map( list(mean, median, sum), get_function_name_as_string )

which would return: [1] "mean" "median" "sum"

I have tried:

map( list(mean, median, sum), ~deparse(substitute(.)) )

but this would give me:

[[1]] [1] "..1"

[[2]] [1] "..1"

[[3]] [1] "..1"

Solving this would allow me to dynamically assign the names of the summary functions to a list containing the summarised data:

my_func <- list( mean, median, sum) 

 

tables <- map( my_func,  
                 function(func){  iris %>%  
                               group_by(Species) %>%
                               summarise( across( contains("."), func)) %>%
                               ungroup()
} )

# instead of hard coding the names of the functions here, 
# I can dynamically generate the names using my_func.
names(tables) <- c("mean", "median", "sum")

# so instead I can use:
names(tables) <- map(my_func, get_function_name_as_string)



Solution

  • I know this is not exactly what you ask, but I think there are better alternatives to your proposed method.

    Why not just create a list of functions, then call it using regular dplyr synthax? It is usually safer and much easier to implement if you use the actual objects rather than extracting their names only to call them by name later on.

    You can map() with my_func() as the .x argument.

    As an example

    1-) Create named list of functions:

    my_func <- list(mean=mean, median=median, sum=sum)
    

    2-) call map()with .x=my_func(), and .xas a placeholder for my_func()at the end of the function call:

    map(.x=my_func, ~iris%>%group_by(Species)%>%summarise(across(contains("."), .x)))
    
    $mean
    # A tibble: 3 x 5
      Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
      <fct>             <dbl>       <dbl>        <dbl>       <dbl>
    1 setosa             5.01        3.43         1.46       0.246
    2 versicolor         5.94        2.77         4.26       1.33 
    3 virginica          6.59        2.97         5.55       2.03 
    
    $median
    # A tibble: 3 x 5
      Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
      <fct>             <dbl>       <dbl>        <dbl>       <dbl>
    1 setosa              5           3.4         1.5          0.2
    2 versicolor          5.9         2.8         4.35         1.3
    3 virginica           6.5         3           5.55         2  
    
    $sum
    # A tibble: 3 x 5
      Species    Sepal.Length Sepal.Width Petal.Length Petal.Width
      <fct>             <dbl>       <dbl>        <dbl>       <dbl>
    1 setosa             250.        171.         73.1        12.3
    2 versicolor         297.        138.        213          66.3
    3 virginica          329.        149.        278.        101.