Unpacking argument lists for ellipsis in R
I am confused by the use of the ellipsis (...
) in some functions, i.e. how to pass an object containing the arguments as a single argument.
In Python it is called "unpacking argument lists", e.g.
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
In R for instance you have the function file.path(...)
that uses an ellipsis. I would like to have this behaviour:
> args <- c('baz', 'foob')
> file.path('/foo/bar/', args)
[1] 'foo/bar/baz/foob'
Instead, I get
[1] 'foo/bar/baz' 'foo/bar/foob'
where the elements of args
are not "unpacked" and evaluated at the same time. Is there a R equivalent to Pythons *arg
?
Solution 1:
The syntax is not as beautiful, but this does the trick:
do.call(file.path,as.list(c("/foo/bar",args)))
do.call
takes two arguments: a function and a list of arguments to call that function with.
Solution 2:
You can extract information from the ellipsis by calling list(...)
inside the function. In this case, the info in the ellipsis is packaged as a list object. For example:
> foo <- function(x,...){
+ print(list(...))
+ }
> foo(1:10,bar = 'bar','foobar')
$bar
[1] "bar"
[[2]]
[1] "foobar"
You can achieve the desired behaviour from vectorised functions like file.path
with a call to do.call
, which is sometimes simpler to use with the wrapper splat
(in the plyr
package)
> args <- c('baz', 'foob')
> library(plyr)
> splat(file.path)(c('/foo/bar', args))
[1] "/foo/bar/baz/foob"
Solution 3:
It took me a while to find it, but the purrr
package has an equivalent to plyr::splat
: it's called lift_dl
.
The "dl" in the name stands for "dots to list", as it's part of a series of lift_xy
functions that can be used to "lift" the domain of a function from one kind of input to another kind, these "kinds" being lists, vectors and "dots".
Since lift_dl
is probably the most useful of those, there is a simple lift
alias provided for it.
To reuse the above example:
> library(purrr)
> args <- c('baz', 'foob')
> lift(file.path)(c('/foo/bar', args))
[1] "/foo/bar/baz/foob"