views:

114

answers:

3

I am looking to assign objects in a loop. I've read that some form of eval(parse( is what I need to perform this, but I'm running into errors listing invalid text or no such file or directory. Below is sample code of generally what I'm attempting to do:

x <- array(seq(1,18,by=1),dim=c(3,2,3))
for (i in 1:length(x[1,1,])) {
  eval(parse(paste(letters[i],"<-mean(x[,,",i,"])",sep="")
}

And when I'm finished using these objects, I would like to remove them (the actual objects are very large and cause memory problems later on...)

for (i in 1:length(x[1,1,])) eval(parse(paste("rm(",letters[i],")",sep="")))

Both eval(parse(paste( portions of this script return errors for invalid text or no such file or directory. Am I missing something in using eval(parse(? Is there a easier/better way to assign objects in a loop?

+2  A: 

Very bad idea; you should never use eval or parse in R, unless you perfectly know what you are doing.
Variables can be created using:

name<-"x"
assign(name,3) #Eqiv to x<-3

And removed by:

name<-"x"
rm(list=name)

But in your case, it can be done with simple named vector:

apply(x,3,mean)->v;names(v)<-letters[1:length(v)]
v
v["b"]
#Some operations on v
rm(v)
mbq
Er, um... never using `eval` is a good idea in some languages, but computing on the language is one of R's strengths... http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html#Computing-on-the-language But yes in this context, assign is preferred.
Vince
@Vince It was in a sense never use `eval` until you are advanced ;-)
mbq
fortune(106): "If the answer is parse() you should usually rethink the question." -- Thomas Lumley, R-help (February 2005)
Joshua Ulrich
@Joshua I was just looking for it.
mbq
@mbq I had a feeling you were referring to that, so I searched for it too.
Joshua Ulrich
+4  A: 

That's a pretty disgusting and frustrating way to go about it. Use assign to assign and rm's list argument to remove objects.

> for (i in 1:length(x[1,1,])) {
+   assign(letters[i],mean(x[,,i]))
+ }
> ls()
[1] "a" "b" "c" "i" "x"
> a
[1] 3.5
> b
[1] 9.5
> c
[1] 15.5
> for (i in 1:length(x[1,1,])) {
+   rm(list=letters[i])
+ }
> ls()
[1] "i" "x"
> 

Whenever you feel the need to use parse, remember fortune(106):

If the answer is parse() you should usually rethink the question.
-- Thomas Lumley, R-help (February 2005)

Joshua Ulrich
I'm adding "creator of disgusting and frustrating code" in my bio.
JD Long
I'll be adding that to my bio as well.
+2  A: 

It is best to avoid using either eval(paste( or assign in this case. Doing either creates many global variables that just cause additional headaches later on.

The best approach is to use existing data structures to store your objects, lists are the most general for these types of cases.

Then you can use the [ls]apply functions to do things with the different elements, usually much quicker than looping through global variables. If you want to save all the objects created, you have just one list to save/load. When it comes time to delete them, you just delete 1 single object and everything is gone (no looping). You can name the elements of the list to refer to them by name later on, or by index.

Greg Snow
I think Gregs suggestion with lists is a pretty reasonable solution. I use it for my work and it works out well, especially in concert with lapply.
Roman Luštrik