Mich55
Mich55

Reputation: 113

R: last argument in elipsis

I have a function f that takes three arguments, and returns the last one. For example:

f <- function(x,y,z){
    return(z)
}
f(11,22,33) #yields 33

However, later on I may have more/less than three arguments, so I want to create a function g that returns the last argument of ...

g <- function(...){
    #return final argument in '...'
}

g(11,22) #should yield 22
g(11,22,33,44,'abc') #should yield 'abc'

Is there any simple way to do this?

I've looked at existing posts on using ..., but they all seem to use it to pass all the arguments to another function (which is not what I'm trying to do).

I could just make the argument into a vector, and return the last element, but I'd like to avoid that if possible.

Upvotes: 0

Views: 97

Answers (2)

G. Grothendieck
G. Grothendieck

Reputation: 269852

Use ...length and ...elt like this:

f <- function(...) ...elt(...length())
f(11, 12, 13)
## [1] 13

Upvotes: 2

r2evans
r2evans

Reputation: 160597

g <- function(...) {
  dots <- list(...)
  if (length(dots)) dots[[length(dots)]]
}

g(11,22)
# [1] 22

g(11,22,33,44,'abc')
# [1] "abc"

g()  # returns nothing, NULL invisibly

I often choose to assign to dots or similar in the function and then deal with it, though that can be both good and bad. If you want to pass the args on to other functions, then you can still use ... as before (or you can use do.call(..), though that's not your question). One side-effect is that by doing this, the ... are evaluated, which though generally fine, in some corner-cases this evaluation may be too soon.

A demonstration:

g(stop("quux"), "abc")
# Error in g(stop("quux"), "abc") : quux

If you want to avoid early evaluation of other args, you can use match.call:

g <- function(...){
  cl <- match.call(expand.dots = TRUE)
  if (length(cl) > 1) cl[[length(cl)]]
}

g()  # nothing

g(1)
# [1] 1

g(stop("quux"), "abc")
# [1] "abc"

Upvotes: 1

Related Questions