6

I am working on a project where I have to do a lot of repeating and life would be a lot easier if i could address multiple objects in a for loop. To elleborate my question i have come up with a (silly) example

For instance if have done this to create my data:

for (i in 1:10)
  {
assign(paste("Season",i, sep = ""),rnorm(10,0,1))
}

So I have Season1, Season2,..,Season10. Is it possible to change the first number of the 10 objects to zero using a for loop. Semi pseudocode looks like this. But of course this does not work.

for (i in 1:10)
  {
Seasoni[1]<-0
}

Anyone with a solution?

Stefan

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
UserX
  • 115
  • 1
  • 1
  • 6
  • 3
    The solution is to not store your data in separate objects named Season1, Season2, etc. but to put them all in a list. Then you can operate on them all as a group using tools like `lapply`. – joran Oct 08 '13 at 18:24

2 Answers2

19

The direct solution to your question would be to use get with paste

for(i in 1:10)  
{
    Object = get(paste0("Season", i))
    Object[1] = 0
    assign(paste0("Season", i), Object)
}

But don't do this.

It's a horrible use of R. As suggested in the comments, store results in lists:

Seasons = lapply(rep(10,10), rnorm) #Generate data
Seasons

Then apply functions:

Seasons = lapply(Seasons, replace, list=1, values=0)
Señor O
  • 17,049
  • 2
  • 45
  • 47
  • Can you explain why it is a horrible use of R? I found this question trying to figure out how to loop through a set of arrays, the names of which I have stored as elements in a character vector. Unfortunately, I also don't really see how to apply these solutions to my problem at hand. – The_Tams Dec 02 '21 at 15:59
  • @The_Tams in general if you are using for loops in R you're not taking advantage of its built in vectorization. For loops in R will often carry a TON of overhead and take forever. (Side note: at my first job I was given R code that took 5 hours to run. As I learned more about it a changed the for loop to a 'lapply' function and got it to run in **less than 5 minutes**) – Señor O Dec 11 '21 at 06:23
  • @The_Tams a great use of R for datasets from 12 seasons is a list called Seasons with 12 elements. Loops over it with `lapply(Seasons, function)`. R is **not** meant to have a ton of global variables - instead of Season1 Seaons2 etc you should definitely have a list of seasons. So OP committed 2 cardinal sins of R - trying to use one sin to solve the other - which is why the misuse will be so glaring to a seasoned R user – Señor O Dec 11 '21 at 06:37
  • So it is inefficient computationally due to the underlying way R works. Our code would be more efficient if we reduce the global variables by combining them (in my case into a larger array), and then use the apply family to run a function over each element, rather than a for loop. For those like me who have had to self-teach R, for loops are intuitive and aren't problematic on the small data sets used for learning. Having resolved my issue and not really seeing how to do it with these functions, I won't rewrite it now, but I will add 'apply' to the ever growing list of 'Things to Learn'. – The_Tams Dec 15 '21 at 17:18
2

Here's a solution based on @joran's comment

> set.seed(1) # for reproducibility
> # the following does the same as your `for` loop and returned value is a list
> Season.list <- replicate(10, rnorm(10, 0, 1), simplify=FALSE) 
> # giving some names
> names(Season.list) <- paste0("Season", 1:length(Season.list))
> # setting first element to 1    
> Season.list <- lapply(Season.list, function(x) {x[1] <- 0; x})
> list2env(Season.list, envir = .GlobalEnv) # will give you each `Season` as you  want :D

Also, another way to do it,

> set.seed(1)
> Season <- replicate(10, rnorm(10, 0, 1))  # the returned object is a matrix
> colnames(Season) <- paste0("Season", 1:ncol(Season))
> Season[1,] <- 0  

If you want to have a vector for each Season then use attach (not a good idea)

> attach(as.data.frame(Season))
> Season1
 [1]  0.0000000  0.1836433 -0.8356286  1.5952808  0.3295078 -0.8204684  0.4874291  0.7383247  0.5757814 -0.3053884
> Season2
 [1]  0.00000000  0.38984324 -0.62124058 -2.21469989  1.12493092 -0.04493361 -0.01619026  0.94383621  0.82122120
[10]  0.59390132
Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138