Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using get() with replacement functions

Can anyone explain to me why the following example occurs?

#Create simple dataframe
assign( "df" , data.frame( P = runif(5) , Q = runif(5) , R = runif(5) ) ) 

#Return the dataframe from the given character vector
get( "df" ) 
            P          Q          R
1  0.17396222 0.90994676 0.90590685
2  0.33860092 0.98078739 0.38058921
3  0.80751402 0.93229290 0.82853094
4  0.05460417 0.55448507 0.01605027
5  0.04250316 0.03808318 0.40678270

#Return the column names of df
colnames( get( "df" ) )
[1] "P" "Q" "R"

#But using a replacement function...
colnames( get( "df" ) ) <- c( "S" , "T" , "U" ) 
    Error in colnames(get("df")) <- c("S", "T", "U") : 
    target of assignment expands to non-language object

I'd A) like to know why the replacement functions won't work in this way with get()?

And b) if there is some way to work around this, given my problem which I outline below;

My problem is that I have many objects, created (using a toy example) in a loop, something like this: assign( paste( "Object" , i , sep = "." ) , rnorm(1000 , i) ), where i is a vector, say i <- 1:1000 and then I would like to be able to assign names (for instance from a different vector) to each object in the loop, but names( get( paste( "Object" , i , sep = "." ) ) <- someNewName doesn't work as in the example above.

But get( paste( "Object" , i , sep = "." ) ) does return the names (or NULL) of those objects.

Thanks!

like image 867
Simon O'Hanlon Avatar asked Jan 22 '13 17:01

Simon O'Hanlon


People also ask

What is the use of REPLACE() function?

REPLACE replaces part of a text string, based on the number of characters you specify, with a different text string.

Is a function that replaces a real implementation of an existing function?

We can use mock functions when we want to replace a specific function return value. Or when we want to check if our test subject is executing a function in a certain way. We can mock a standalone function or an external module method, and we can provide a specific implementation.


2 Answers

To understand why this doesn't work, you need to understand what colnames<- does. Like every function in that looks like it's modifying an object, it's actually modifying a copy, so conceptually colnames(x) <- y gets expanded to:

copy <- x
colnames(copy) <- y
x <- copy

which can be written a little more compactly if you call the replacement operator in the usual way:

x <- `colnames<-`(x, y)

So your example becomes

get("x") <- `colnames<-`(get("x"), y)

The right side is valid R, but the command as a whole is not, because you can't assign something to the result of a function:

x <- 1
get("x") <- 2
# Error in get("x") <- 2 : 
#  target of assignment expands to non-language object
like image 71
hadley Avatar answered Oct 13 '22 00:10

hadley


Using assign in the way you demonstrate in the question is at least uncommon in R. Normally you would just put all objects in a list.

So, instead of

for (i in 1:10) {
assign( paste( "Object" , i , sep = "." ) , rnorm(1000 , i) )}

you would do

objects <- list()
for (i in 1:10) {
objects[[i]] <- rnorm(1000 , i) }

In fact, this construct is so common that there is a (optimized) function (lapply), which does something similar:

objects <- lapply(1:10, function(x) rnorm(1000,x))

You can then access, e.g., the first object as objects[[1]] and there are several functions for working with lists.

like image 22
Roland Avatar answered Oct 13 '22 01:10

Roland