Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: get names of arguments passed in `...`

In a simple function using ... to supply a list of arguments, is it possible for that function to find the names of the objects passed from the calling environment? If so, how?

This arises in the context of the question, printing matrices and vectors side by side, but is probably more general.

In that context, the arguments ... can also include character strings, for which no names are required. Here is my MWE, where I tried using deparse(substitute()), but to no avail.

test_names <- function(...) {
  # get arguments
  args <- list(...)
  chars <- sapply(args, is.character)
  names <- sapply(args, function(x) if(is.character(x)) " " else deparse(substitute(x)))
  names
}

Test:

A = matrix(c(0.5, 1, 3, 0.75, 2.8, 4), nrow = 2)
x = c(0.5, 3.7, 2.3)
y = c(0.7, -1.2)
b = A %*% x - y

> test_names(A, " * ", x, " - ", y, " = ", b)
[1] "X[[i]]" " "      "X[[i]]" " "      "X[[i]]" " "      "X[[i]]"
> 

My desired output for this would be the character vector of length 7:

[1] "A"  " "   "x" " "  "y" " "   "b"

It is surprising here that the results are all X[[i]], when there is no X mentioned anywhere.

Following @Roland's answer, this seems to do what I want:

test_names2 <- function(...) {
  argnames <- sys.call()
  unlist(lapply(argnames[-1], as.character))
}

> test_names2(A, " * ", x, " - ", y, " = ", b)
[1] "A"   " * " "x"   " - " "y"   " = " "b"  
like image 956
user101089 Avatar asked Sep 14 '16 17:09

user101089


2 Answers

As the email list describes (here) either sys.call as Roland said or match.call can be used for this.

In comparison to Roland's solution, a solution with match.call looks like

f = function(...){
  return(match.call())
}

d = f(x = 1, b = 5)
d
#f(x = 1, b = 5)
as.list(d[-1])
#$x
#[1] 1
#
#$b
#[1] 5

So use it somewhat like this, because the first element is the name of the function itself.

f = function(...){
  return(as.list(match.call())[-1])
}

They are similar, but the help page says:

sys.call() is similar [to match.call()], but does not expand the argument names;

So here's one difference.

like image 146
catastrophic-failure Avatar answered Oct 08 '22 23:10

catastrophic-failure


Use sys.call:

test_names <- function(...) {
  argnames <- sys.call()
  paste(lapply(argnames[-1], as.character), collapse = "")
}
#[1] "A * x - y = b"
like image 22
Roland Avatar answered Oct 09 '22 00:10

Roland