Ben
Ben

Reputation: 21625

How pass unknown set of parameters to R function

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

Answers (2)

josliber
josliber

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

Dirk is no longer here
Dirk is no longer here

Reputation: 368261

I prefer the newer docopt over optparse as I found docopt to be

  • easier to use (see below)
  • widely available for many langauages, see docopt.org

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

Related Questions