32

I wonder if there is a simple way to produce a list of variables using a for loop, and give its value.

for(i in 1:3)
{
  noquote(paste("a",i,sep=""))=i
}

In the above code, I try to create a1, a2, a3, which assign to the values of 1, 2, 3. However, R gives an error message. Thanks for your help.

Rob Hyndman
  • 51,928
  • 23
  • 126
  • 178
Han Lin Shang
  • 321
  • 1
  • 4
  • 3
  • 3
    I doubt you you have to do this -- it seems you're making something in a very wrong way. –  May 16 '11 at 09:36
  • @mbq, in [Eviews](http://www.eviews.com) for example this is pretty normal coding practice. Not that I am advocating it, Eviews rates only a bit lower than Excel in my top evil software list :) – mpiktas May 16 '11 at 10:24
  • 7
    @mpiktas In R, it is more natural to make a list, set its `names` parameter and later either just use it, `attach` it or convert it into an environment with `list2env` and `eval` inside it. With no loops, parse or other ugly stuff. –  May 16 '11 at 10:38
  • @mbq, hm, `list2env` is a relatively new function. And still it will produce the variables in the some environment, when the OP wants to get the variables in the top environment. So the ugliness still remains :) – mpiktas May 16 '11 at 10:49
  • Variables in `.GlobalEnv` is precisely what I try to omit. –  May 16 '11 at 11:52
  • @mbq, why? I can understand that there are specific scenarios when this is not desirable, but in general why not? – mpiktas May 16 '11 at 12:01
  • 4
    For future questions of a similar nature, I'd suggest that this kind of question actually belongs on StackOverflow. The question has nothing to do with statistics per se. – Mars Apr 16 '15 at 19:21

2 Answers2

46

Your are looking for assign().

for(i in 1:3){
  assign(paste("a", i, sep = ""), i)    
}

gives

> ls()
[1] "a1"          "a2"          "a3" 

and

> a1
[1] 1
> a2
[1] 2
> a3
[1] 3

Update

I agree that using loops is (very often) bad R coding style (see discussion above). Using list2env() (thanks to @mbq for mentioning it), this is another solution to @Han Lin Shang's question:

x <- as.list(rnorm(10000))
names(x) <- paste("a", 1:length(x), sep = "")
list2env(x , envir = .GlobalEnv)
Bernd Weiss
  • 7,044
  • 28
  • 40
23

If the values are in vector, the loop is not necessary:

vals <- rnorm(3)
n    <- length(vals)
lhs  <- paste("a",    1:n,     sep="")
rhs  <- paste("vals[",1:n,"]", sep="")
eq   <- paste(paste(lhs, rhs, sep="<-"), collapse=";")
eval(parse(text=eq))

As a side note, this is the reason why I love R.

gung - Reinstate Monica
  • 132,789
  • 81
  • 357
  • 650
mpiktas
  • 33,140
  • 5
  • 82
  • 138
  • 4
    `library(fortunes)` `fortune(106)` – Roman Luštrik May 16 '11 at 12:18
  • @Roman, strange, I've started using `parse` after reading R help pages. I agree that sometimes it is an overkill, for example in `formula` management, but I found it very useful. Note that I cannot rethink the question as suggested in the fortune, since I did not ask it. – mpiktas May 16 '11 at 12:28
  • @Roman, I see that there are at least 3 people which do not like to use `parse`, yet nobody gave clear reason why. Is it slow? Prone to errors? Too sophisticated? I usually use it as analogue of `source`. – mpiktas May 16 '11 at 12:31
  • 1
    @mpiktas : it has to do with the fact that the underlying scoping rules can result in inpredictable results when used within a function. Also (as mentioned in the help files), R and S can give a different result due to the difference in scoping rules. It is also slower than other solutions. This will matter when you have to do this many times. And last but not least, in most cases there is a more elegant and easier solution than using eval(parse()). In this case that's working with lists or using assign. – Joris Meys May 16 '11 at 12:40
  • @Joris, ok this is clearly R and the code is not in a function :) In this case I used `parse` as a substitute for running a code which I created using string manipulation instead of writing the code by hand. I fail to see the deficiencies of `parse` in this scenario, since this is the way R is used, you write some code and then you run it. – mpiktas May 16 '11 at 12:53
  • 1
    @mpiktas : I never said it's deficient. I just gave you the reason why in general a eval(parse()) construct is advised against by eg Thomas Lumley, member of the R core development team. (cfr the refernce of @Roman Lustrik) – Joris Meys May 16 '11 at 13:06
  • @Joris, thanks for your explanations. I just felt a bit stupid, since I use `parse` extensively mainly for reasons given in this [example](http://stats.stackexchange.com/questions/8243/program-to-compute-partial-derivatives/8253#8253). I do not think that besides automatic differentiation (which is not yet implemented fully) you can produce more elegant code. I would however be glad to be proven wrong. – mpiktas May 16 '11 at 13:12
  • @mpiktas : Your link is an example where the use of parse is the right choice. Note that you never used `eval()` there, you use parse (correctly) to convert a string to an expression object needed by the `deriv()` function. That's a whole other beast than the problem of OP. Nice piece of code by the way. – Joris Meys May 16 '11 at 13:25
  • elegant workspaces are nice too n – mdsumner May 16 '11 at 13:25
  • @Joris, I use `eval` later in the code to evaluate the function :) Though I take care to use the correct environment. – mpiktas May 16 '11 at 13:36
  • @mdsumner, your code produces named vector, when the OP wants variables with certain names in the global environment. – mpiktas May 16 '11 at 13:37
  • 1
    exactly, bad practice like using assign to create multiple single element variables should be discouraged – mdsumner May 19 '11 at 23:27
  • @mdsumner, why is it a bad practice? – mpiktas May 20 '11 at 03:33
  • Ok this is bizarre, why the downvote? My answer clearly solves the problem (I've tested it), and I've given the arguments why this particular piece of code is acceptable. It does not involve any fancy hackery it is plain R. – mpiktas May 20 '11 at 20:07