Reputation: 2321
I have an R function which takes a large number of arguments (18) which I would like to pass in as a list. When I am running this function by hand, so to speak, I generally want to use all the defaults but one or two, but I also want to run this same function many times with various combinations of default and non-default items, which I would like to assemble programmatically as lists.
I know that I could just have my 18+ arguments as individual formals and then assemble them into a list inside the function, but I wish I could have a list as a default for a formal, and then have the elements have defaults as well. Like this:
> f <<- function(x, y = list(a=0, b=3)) {with(y, (x + a + b))}
> f(1)
[1] 4
> f(x=1, y$a = 1)
Error: unexpected '=' in "f(x=1, y$a ="
(or alternatively)
In y$a <- 1 :
Error in eval(substitute(expr), data, enclos = parent.frame()) :
object 'a' not found
except with the output of 5 rather than an error. I suspect there is no way to do this, because R does not recognise the assignments in the list as creating defaults, but only as creating named elements. But maybe with the assignment form of formals? or through some clever use of do.call?
Upvotes: 1
Views: 273
Reputation: 270438
Here are some alternatives:
1) modifyList Use modifyList
to process the defaults.
f1 <- function(x, y = list()) {
defaults <- list(a = 0, b = 3)
with(modifyList(defaults, y), {
x + a + b
})
}
f1(x = 1)
## [1] 4
f1(x = 1, y = list(a = 1))
## [1] 5
2) do.call Another possibility is to have two functions. The first does not use a list and the second (which is the one the user calls) does using do.call
to invoke the first.
f2impl <- function(x, a = 0, b = 3) x + a + b
f2 <- function(x, y = list()) do.call("f2impl", c(x, y))
f2(x = 1)
## [1] 4
f2(x = 1, y = list(a = 1))
## [1] 5
Upvotes: 1