Rich Scriven
Rich Scriven

Reputation: 99331

Substitute an unevaluated argument into multiple functions

Consider the following function foo. I'd like to hard-code na.rm = TRUE into each of the calls in the list that returns the result, but I only want to write it once. My current implementation does not work.

foo <- function(x) {
    e <- expression(na.rm = TRUE)
    list(sum(x, eval(e)), mean(x, eval(e)), sd(x, eval(e)))
}

I do not want to use ... in the argument list for this function. I don't want to give the user the option to add an na.rm argument. The problem with the above code is that

> eval(expression(na.rm = TRUE))
# [1] TRUE

and therefore the TRUE is passed to the trim argument in mean, instead of na.rm

> foo(c(1, NA, 3))
# Error in mean.default(x, eval(e)) : 'trim' must be numeric of length one

Is there a way to pass the argument as an expression, perhaps with quote or substitute, so that R would read the argument as na.rm = TRUE instead of just TRUE ?

Note: My actual function is using quiet = TRUE five times in seven lines, so the code would be cleaner if I could just write the expression once, and pass it to each of the five functions.

Upvotes: 3

Views: 95

Answers (3)

Joris Meys
Joris Meys

Reputation: 108523

I don't really know whether this is a good idea in any case, but what you want to do can be done with do.call :

foo <- function(x) {
  args <- list(quote(x),na.rm=TRUE)
  list(
    do.call(sum,args), 
    do.call(mean, args),
    do.call(sd, args)
  )
}

As Hadley said in the comments, you don't want to copy x completely in the list args, as that can give memory problems when x is big. Hence the use of quote() (thx Hadley)

This gives:

> foo(c(1, NA, 3))
[[1]]
[1] 4

[[2]]
[1] 2

[[3]]
[1] 1.414214

Upvotes: 4

akrun
akrun

Reputation: 887048

You could try:

fun1 <- function(x) {
    lapply(c(sum, mean, sd), do.call, list(x, na.rm=TRUE))
}

fun1(c(1,NA,3))
#[[1]]
#[1] 4

#[[2]]
#[1] 2

#[[3]]
#[1] 1.414214

Upvotes: 3

Sven Hohenstein
Sven Hohenstein

Reputation: 81683

You can exclude the NAs before using the functions:

foo <- function(x) {
    x2 <- na.omit(x)
    list(sum(x2), mean(x2), sd(x2))
}

Another possibility is to use lapply with the functions you want to use:

foo <- function(x) {
   lapply(c(sum, mean, sd), function(f) f(x, na.rm = TRUE))
}

Upvotes: 3

Related Questions