Using Substitute to Get Argument Name

using substitute to get argument name with

The canonical idiom here is deparse(substitute(foo)), but the ... needs slightly different processing. Here is a modification that does what you want:

foo <- function(a, ...) {
arg <- deparse(substitute(a))
dots <- substitute(list(...))[-1]
c(arg, sapply(dots, deparse))
}

x <- 1
y <- 2
z <- 3

> foo(x,y,z)
[1] "x" "y" "z"

base R substitute names of the arguments to function call

Assuming that the question is how to produce a call object whose function is the first argument of params, whose single argument name is the value of the second component of params and whose argument value is the third component of params then c2 is that call object. We verify that the cakl object produced is identical to the rlang call object shown in the question.

c2 <- as.call(setNames(params, c("", "", params2$my_name))[-2])

# verify that c2 equals the output of the rlang example in question
c1 <- with(expr = rlang::call2(my_fun, !!my_name := my_value), data = params)

identical(c1, c2)
## [1] TRUE

This generalizes so that if the call has more arguments so that params has length n+2 and the second component of params is a vector of names whose length is n then it still works.

If you have control over the input I think it would make more sense to define the input list as having one component for the function name and one component for each argument with the names of the components being the argument names (as opposed to a separate argument to hold the names). In that case we could simply write the following. Actually what the above does is to transform params into that form and then use as.call so we might as well provide that form from the start if possible.

as.call(params2)  # params2[[1]] is func name, params2[-1] is named args

Note

To execute the call just use:

eval(c2)

or we could use do.call:

do.call(as.character(params[[1]]), setNames(tail(params, -2), params[[2]]))

Use substitute() to replace a label/argument name

x is bound to a name. We can see that with

as.list(substitute(list(x = y)))
# [[1]]
# list
#
# $x
# y

So it's not terribly easy to change the name within the substitute call. But you can do

e <- substitute(list(x = y), list(y = "bar"))
names(e)[2] <- "foo"
eval(e)
# $foo
# [1] "bar"

or with just substitute you can change the expression to use setNames

e <- substitute(setNames(list(y), x), list(x = "foo", y = "bar"))
eval(e)
# $foo
# [1] "bar"

But you can also use call, which is easier

cl <- call("list", foo = "bar")
eval(cl)
# $foo
# [1] "bar"

deparse and substitute on ellipsis to get names of parameters

As a workaround try this

foo <- function(...) {
x <- substitute(...())
if(class(x[[1]]) == "call") sapply(x[[1]][-1] , deparse)
else sapply(x , deparse)
}

  • Output
> foo(list(a, b))
[1] "a" "b"

> foo(a, b)
[1] "a" "b"

Get argument name instead of value in a function in R

We can use deparse/substitute

testFun <- function(x = a_vector) {
deparse(substitute(x))
}

testFun()
#[1] "a_vector"

R user-defined save load functions | Passing variable names as arguments using deparse(substitute)

You need to do the changes in both save and load functions. Use list argument in save function to save the data with the same variable names as passed value.

getSave <- function(folder, rdata){
val <- deparse(substitute(rdata))

save(list = val,
file = paste0("./", deparse(substitute(folder)), "/", val, ".RData"))
}

getSave(SData, x)
getSave(SData, y)

To load the data, specify the environment as global since by default the values are loaded in the called environment. Since you are loading the data in a function by default the values are loaded inside the function only.

getLoad <- function(folder, rdata){
load(paste0("./", deparse(substitute(folder)), "/", deparse(substitute(rdata)), ".RData"),
envir = .GlobalEnv)
}

getLoad(SData, x)
getLoad(SData, y)

So the issue was not related to deparse, substitue but how save and load functions work inside a user defined function.

deparse(substitute()) returns function name normally, but function code when called inside for loop

As soon as you use x inside your function, it is evaluated, so it "stops being an (unevaluated) expression" and "starts being its resulting values (evaluated expression)". To prevent this, you must capture x by substitute before you use it for the first time.

The result of substitute is an object which you can query as if it was a list. So you can use

x <- substitute(x)

and then x[[1]] (the function name) and x[[2]] and following (the arguments of the function)

So this works:

ds2 <- function(x) {
x <- substitute(x)
# you can do `x[[1]]` but you can't use the expression object x in a
# for loop. So you have to turn it into a list first
for (y in as.list(x)[-1]) {
print(deparse(y))
}
}
ds2(c(square,sum))
## [1] "square"
## [1] "sum"

How to get name of variable in R (substitute)?

I suggest you consider passing optional name value to these functions. I say this because it seems like you really want to use the name as a label for something in the end result; so it's not really the variable itself that matters so much as its name. You could do

fun1 <- function (some_variable, name=deparse(substitute(some_variable))) {
name
}
fun2 <- function (var_pass, name=deparse(substitute(var_pass))) {
fun1 (var_pass, name)
}
my_var <- c(1,2)

fun2(my_var)
# [1] "my_var"

fun1(my_var)
# [1] "my_var"

This way if you end up having some odd variable name and what to give a better name to a result, you at least have the option. And by default it should do what you want without having to require the name parameter.



Related Topics



Leave a reply



Submit