In R, How to Get an Object'S Name After It Is Sent to a Function

In R, how to get an object's name after it is sent to a function?

The old deparse-substitute trick:

a<-data.frame(x=1:10,y=1:10)
test<-function(z){
mean.x<-mean(z$x)
nm <-deparse(substitute(z))
print(nm)
return(mean.x)}

test(a)
#[1] "a" ... this is the side-effect of the print() call
# ... you could have done something useful with that character value
#[1] 5.5 ... this is the result of the function call

Edit: Ran it with the new test-object

Note: this will not succeed inside a local function when a set of list items are passed from the first argument to lapply (and it also fails when an object is passed from a list given to a for-loop.) You would be able to extract the ".Names"-attribute and the order of processing from the structure result, if it were a named vector that were being processed.

> lapply( list(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a # This "a" and the next one in the print output are put in after processing
$a[[1]]
[1] "X" "" "1L]]" # Notice that there was no "a"


$b
$b[[1]]
[1] "X" "" "2L]]"

> lapply( c(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a
$a[[1]] # but it's theoretically possible to extract when its an atomic vector
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "1L]]"


$b
$b[[1]]
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "2L]]"

Get object name in R as string

I hope I've understood correctly:

myfun <- function(month) {
deparse(match.call()$month)
}

january <- 1

myfun(january)
#[1] "january"

Regarding your "Summarizing" example: It's not possible.

I suspect your question is lacking a representative example. You've minimized too much.

How to get the original name of a object when sending a list of objects to a function

This is kind of a hack :

return_name <- function(data){
strsplit(gsub('list|[()]', '', deparse(substitute(data))), ',\\s*')[[1]]
}

return_name(list(my_data, my_data_2))
#[1] "my_data" "my_data_2"
return_name(my_data_1)
#[1] "my_data_1"

R get object name when is input of another function

Can you share your code? I have no problem getting the output.

new_object = 10
new_object
[1] 10

fun1 <- function(fun_input) {
deparse(substitute(fun_input))
}

fun1(new_object)
[1] "new_object"

R object's name carrying through multiple functions

What's really the purpose here? If you are just using one function as a wrapper to another, then there are better ways of preserving arguments. For example

test_object <- function(x, y, z) {
call <- match.call()
call[[1]] <- quote(new_test_object)
eval(call)
}

But in general relying on deparse() to get information from names of variables isn't a very reliable method. It would be better to have such pieces of information be proper parameters that you can set if you like. This makes your functions much more flexible.

test_object <- function(x, y, z, xname=deparse(substitute(x))) {
new_test_object(x, y, z, xname=xname)
}

new_test_object <- function(x, y, z, xname=deparse(substitute(x))) {
structure(list(x = x,
y = y,
z = z,
x_name = xname),
class = "test_object")
}

Getting the name of object passed to `print` when calling object directly (not expressing the `print` function)

It is easier to explain what's going on than it is to fix it. If we start by looking at the generic print we can see it simply dispatches the class-appropriate print method via UseMethod("print"):

print
#> function (x, ...)
#> UseMethod("print")

So when you call print(obj), you are calling the generic function print(obj) first, which then calls print.new_obj(obj). We can confirm this by adding print(sys.calls()) to your print method:

print.new_obj <- function(y){
print(sys.calls())
cat("New object name:\n")
cat(deparse(substitute(y)))
}

print(obj)
#> [[1]]
#> print(obj)
#>
#> [[2]]
#> print.new_obj(obj)
#>
#> New object name:
#> obj

So far, so good, and I suspect you already knew all this.

What happens now, when you just type obj into the console?

obj
#> [[1]]
#> (function (x, ...)
#> UseMethod("print"))(x)
#>
#> [[2]]
#> print.new_obj(x)
#>
#> New object name:
#> x

Now we can see where the x comes from. It is taken from a behind-the-scenes call to the generic print which is actually called as an unnamed function. Hence the name of the variable is not actually included in the call stack. There are other questions on SO where it says this makes the problem insoluble. This isn't true; it just means you will need to look outside of the call stack for your object:

print.new_obj <- function(y){
obj_name <- deparse(substitute(x, parent.frame()))
if (obj_name != "x")
{
obj_name <- names(which(sapply(ls(envir = parent.frame(2)), function(v)
identical(y, get(v, envir = parent.frame(2))))))[1]
cat("New object name:\n", obj_name)
}
else cat("New object name:\n", deparse(substitute(y)))
}

print(obj)
#> New object name:
#> obj
obj
#> New object name:
#> obj

Of course, you wouldn't want to use this in production code, for all sorts of reasons. It is not particularly useful or logical for a data structure to know what name it has been assigned in a particular environment, and would not be an idiomatic way to write a package for other users.

Still, nice to know it is possible.

How to convert variable (object) name into String

You can use deparse and substitute to get the name of a function argument:

myfunc <- function(v1) {
deparse(substitute(v1))
}

myfunc(foo)
[1] "foo"

How do I access the name of the variable assigned to the result of a function within the function?

I think that it's not strictly possible, as other solutions explained, and the reasonable alternative is probably Yosi's answer.

However we can have fun with some ideas, starting simple and getting crazier gradually.


1 - define an infix operator that looks similar

`%<-add_str%` <- function(e1, e2) {
e2_ <- e2
e1_ <- as.character(substitute(e1))
eval.parent(substitute(e1 <- paste0(e1_,e2_)))
}

a %<-add_str% "b"
a
# "ab"

2 - Redefine := so that it makes available the name of the lhs to the rhs through a ..lhs() function

I think it's my favourite option :

`:=` <- function(lhs,rhs){
lhs_name <- as.character(substitute(lhs))
assign(lhs_name,eval(substitute(rhs)), envir = parent.frame())
lhs
}

..lhs <- function(){
eval.parent(quote(lhs_name),2)
}

add_str <- function(x){
res <- paste0(..lhs(),x)
res
}

a := add_str("b")
a
# [1] "ab"

There might be a way to redefine <- based on this, but I couldn't figure it out due to recursion issues.


3 - Use memory address dark magic to hunt lhs (if it exists)

This comes straight from: Get name of x when defining `(<-` operator

We'll need to change a bit the syntax and define the function fetch_name for this purpose, which is able to get the name of the rhs from a *<- function, where as.character(substitute(lhs)) would return "*tmp*".

fetch_name <- function(x,env = parent.frame(2)) {
all_addresses <- sapply(ls(env), pryr:::address2, env)
all_addresses <- all_addresses[names(all_addresses) != "*tmp*"]
all_addresses_short <- gsub("(^|<)[0x]*(.*?)(>|$)","\\2",all_addresses)

x_address <- tracemem(x)
untracemem(x)
x_address_short <- tolower(gsub("(^|<)[0x]*(.*?)(>|$)","\\2",x_address))

ind <- match(x_address_short, all_addresses_short)
x_name <- names(all_addresses)[ind]
x_name
}

`add_str<-` <- function(x,value){
x_name <- fetch_name(x)
paste0(x_name,value)
}

a <- NA
add_str(a) <- "b"
a

4- a variant of the latter, using .Last.value :

add_str <- function(value){
x_name <- fetch_name(.Last.value)
assign(x_name,paste0(x_name,value),envir = parent.frame())
paste0(x_name,value)
}

a <- NA;add_str("b")
a
# [1] "ab"

Operations don't need to be on the same line, but they need to follow each other.


5 - Again a variant, using a print method hack

Extremely dirty and convoluted, to please the tortured spirits and troll the others.

This is the only one that really gives the expected output, but it works only in interactive mode.

The trick is that instead of doing all the work in the first operation I also use the second (printing). So in the first step I return an object whose value is "b", but I also assigned a class "weird" to it and a printing method, the printing method then modifies the object's value, resets its class, and destroys itself.

add_str <- function(x){
class(x) <- "weird"
assign("print.weird", function(x) {
env <- parent.frame(2)
x_name <- fetch_name(x, env)
assign(x_name,paste0(x_name,unclass(x)),envir = env)
rm(print.weird,envir = env)
print(paste0(x_name,x))
},envir = parent.frame())
x
}

a <- add_str("b")
a
# [1] "ab"

(a <- add_str("b") will have the same effect as both lines above. print(a <- add_str("b")) would also have the same effect but would work in non interactive code, as well.



Related Topics



Leave a reply



Submit