Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

do.call in combination with "::"

Tags:

r

I make a lot of use of 'do.call' to generate function calls. E.g:

myfun <- "rnorm";
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

However, sometimes I would like to call a function explicitly from a certain package. Similar to e.g. stats::rnorm(n=10, mean=5). Is there any way I can use do.call, or create a function that behaves just like do.call to get this to work:

myfun <- "stats::rnorm";
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);
like image 770
Jeroen Ooms Avatar asked Apr 05 '12 03:04

Jeroen Ooms


2 Answers

There is no function called "stats::rnorm". You must find the rnorm function in the "stats" namespace:

myfun <- get("rnorm", asNamespace("stats"))
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

Now you can of course also go from a name like "stats::rnorm" and split it into the namespace part and the function name:

funname <- "stats::rnorm"
fn <- strsplit(funname, "::")[[1]]
myfun <- if (length(fn)==1) fn[[1]] else get(fn[[2]], asNamespace(fn[[1]]))
myargs <- list(n=10, mean=5);
do.call(myfun, myargs);

Update I just wanted to show that this approach is 2.5x faster than the one from @Jeroen...

do.call.tommy <- function(what, args, ...) {
  if(is.character(what)){
    fn <- strsplit(what, "::")[[1]]
    what <- if(length(fn)==1) {
        get(fn[[1]], envir=parent.frame(), mode="function")
    } else {
        get(fn[[2]], envir=asNamespace(fn[[1]]), mode="function")
    }
  }

  do.call(what, as.list(args), ...)
}

# Test it
do.call.tommy(runif, 10)
f1 <- function(FUN) do.call.tommy(FUN, list(5))
f2 <- function() { myfun<-function(x) x; do.call.tommy(myfun, list(5)) }
f1(runif)
f1("stats::runif")
f2()

# Test the performance...    
system.time(for(i in 1:1e4) do.call.jeroen("stats::runif", list(n=1, max=50))) # 1.07 secs
system.time(for(i in 1:1e4) do.call.tommy("stats::runif", list(n=1, max=50)))  # 0.42 secs
like image 84
Tommy Avatar answered Oct 05 '22 21:10

Tommy


You can remove the quotes: that will be the function itself, rather than its name.

myfun <- stats::rnorm
myargs <- list(n=10, mean=5)
do.call(myfun, myargs)
like image 45
Vincent Zoonekynd Avatar answered Oct 05 '22 21:10

Vincent Zoonekynd