Home > Software design >  Passing map() .x to a function
Passing map() .x to a function

Time:02-13

This might seem like a silly question, but for the life of me I cannot figure it out so appreciate any help.

I am trying to pass .x (from purrr::map) to a function so in the end I get a list of functions (I will use this eventually to pass a list of column definitions with functions inside to reactable). This is a very basic example of what I want to do:

a = list("b", "c")

t <- map(a, ~{
  function(.x){
    print(x)
  }
})

The result I am looking for is:

> t
[[1]]
function(b){
    print(x)
  }

[[2]]
function(c){
    print(x)
  }

but I get:

> t
[[1]]
function(.x){
    print(x)
  }

[[2]]
function(.x){
    print(x)
  }

Is what I am looking for possible?

CodePudding user response:

You can get what you want by using a wrapper function to create a new function. Within the wrapper, create an empty function, set the args to the value x passed in (so if x="a", with give the equivalent of alist(a=)), and then also parse a string to the body. Then the returned list will be the functions you want.

library(purrr)

function_crafter <- function(x) {
  f <- function() {}
  args <- setNames(list(bquote()), x)
  formals(f) <- args
  body(f) <- parse(text = paste0("print(", x, ")"))
  f
}

a <- list("b", "c")

fl <- map(a, function_crafter)

fl[[1]](b=2)
#> [1] 2
fl[[2]](c=39)
#> [1] 39

fl
#> [[1]]
#> function (b) 
#> print(b)
#> <environment: 0x7fb68752aae0>
#> 
#> [[2]]
#> function (c) 
#> print(c)
#> <environment: 0x7fb687552818>

If you actually wanted the print() in each function to simply be print(x) rather than print(b) or print(c), then that's even easier, just define the body of the function in its initialization.

  • Related