Reputation: 21625
I have a function like
myfunc <- function(x, y=x){
x+y
}
which (obviously) defaults the value of y to x if y is not passed to the function.
Now, I'm using optparse
to read some command line arguments to a script which calls myfunc
.
# myscript.R
option_list <- list(
make_option(c("--x"), type="numeric"),
make_option(c("--y"), type="numeric")
)
print(myfunc(opt$x, opt$y))
The problem with the code above is, it forces the user to provide a value for y (otherwise an error will be thrown). Instead, I'd like to call myfunc
using all and only the parameters provided by the user. How can I accomplish this in the most elegant, scalable, generalize-able way?
Note - for those familiar with Python, I think I want do something similar to dictionary unpacking using whatever values are inside opt
.
Upvotes: 1
Views: 784
Reputation: 44330
If you have a named list of arguments from optparse
that you want to provide to a function, you can do so with do.call
:
# Provide x and y
opts <- list(x=2, y=3)
do.call(myfunc, opts)
# [1] 5
# Provide only x
opts <- list(x=2)
do.call(myfunc, opts)
# [1] 4
As you note, this is basically "dictionary unpacking"/"splatting" from Python.
You could then use optparse
to grab the values for x and y, making y an optional input on the command line:
# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=x) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=2 --y=3
# [1] 5
# > Rscript optparse.R --x=2
# [1] 4
By using the R function being called to compute the default value of y instead of the command-line parser, it is simple to make more complicated defaults for y, such as y=min(0, x)
.
# optparse.R
library(optparse)
option_list <- list(make_option("--x", type="integer", default=0),
make_option("--y", type="integer"))
opt <- parse_args(OptionParser(option_list=option_list))
myfunc <- function(x, y=min(0, x)) x+y
do.call(myfunc, opt[names(opt) %in% c("x", "y")])
# > Rscript optparse.R --x=-2
# [1] -4
# > Rscript optparse.R --x=2
# [1] 2
Upvotes: 3
Reputation: 368261
I prefer the newer docopt over optparse as I found docopt to be
Here is a minimal examples which also provides default values which is your concern here. First the code:
#!/usr/bin/Rscript
library(methods) # as Rscript does not load it
library(docopt)
## simple helper function
myfunc <- function(x, y) as.numeric(x) + as.numeric(y)
doc <- "Usage: myscript [-x x] [-y y]
-x x Numeric value for x [default: 0.0]
-y y Numeric value for y [default: -7.89]"
opt <- docopt(doc)
print(myfunc(opt$x, opt$y))
Then the usage:
edd@max:/tmp$ ./myscript.R --help
Usage: myscript [-x x] [-y y]
-x x Numeric value for x [default: 0.0]
-y y Numeric value for y [default: -7.89]
edd@max:/tmp$ ./myscript.R
[1] -7.89
edd@max:/tmp$ ./myscript.R -y 40 -x 2
[1] 42
edd@max:/tmp$
Note that we have to use as.numeric()
on the values as the one thing that docopt does not do is to guarantee / enforce a type.
Upvotes: 2