Luther_Blissett
Luther_Blissett

Reputation: 327

How to store the results of a for-loop in R when the result is a vector

When looping over a function that produces a vector, I simply want to be able to store the resulting vectors as one long vector.

This does not work:

n_total <- 5
grps <- 2
start_s <- 0.7
start_v <- 0.8
Alpha <- 0.9

cols <- vector()
for(i in seq(grps)){
  if(i > 1){
    start_s <- start_s-0.1
    start_v <- start_v-0.1
  }
  cols[i] <- rainbow(n_total, start_s, start_v, alpha = Alpha)
}

So the result stored in cols should be:

[1] "#B34747E6" "#9DB347E6" "#47B372E6" "#4772B3E6" "#9D47B3E6" "#994D4DE6" "#8A994DE6" "#4D996BE6" "#4D6B99E6" "#8A4D99E6"

i.e. a 1x10 vector of strings.

Upvotes: 1

Views: 561

Answers (3)

akrun
akrun

Reputation: 887851

In the OP's, post, the 'cols' is initialized with a length 0. One option here would to be append the vector while assigning to it in each iteration

cols <- vector()
for(i in seq(grps)){
if(i > 1){
 start_s <- start_s-0.1
  start_v <- start_v-0.1
  }
  cols<- c(cols, rainbow(n_total, start_s, start_v, alpha = Alpha))
}


cols
#[1] "#CC3D3DE6" "#AFCC3DE6" "#3DCC76E6" "#3D76CCE6" "#AF3DCCE6" "#B34747E6" "#9DB347E6" "#47B372E6"
#[9] "#4772B3E6" "#9D47B3E6"

If the OP wanted to run not with a fixed 0.1 to subtract

cols <- vector()
i1 <- seq(0, by = 0.1, length.out = grps)
for(i in seq_len(grps)) {
   if(i > 1){
    start_s <- start_s-i1[i]
     start_v <- start_v-i1[i]
     }  
     cols<- c(cols, rainbow(n_total, start_s, start_v, alpha = Alpha))
  }



cols
#[1] "#B34747E6" "#9DB347E6" "#47B372E6" "#4772B3E6" "#9D47B3E6" "#994D4DE6" "#8A994DE6" "#4D996BE6"
#[9] "#4D6B99E6" "#8A4D99E6"

Instead, it would be more efficient to initialize with a pre-determined length and then do the index assignment. But, here, there are some things uncertain i.e. it is doing an if check and only if that is TRUE, then it is doing the assignment

cols <- character(10)

NOTE: OP's asked for a for loop here. In R, there are better ways to deal with it instead of for loop

Upvotes: 1

Adi Sarid
Adi Sarid

Reputation: 819

Perhaps this isn't what you were expecting (having placed the for-loop tag), but you should refrain from using R for loops when you can. Instead get used to using vectorized operations for iterations. They are much more efficient and produce a more readable code. One option is using mapply here is another approach using map (the purrr package).

The tibble function creates the bases for the iteration (the iterator if you will).

The combination of mutate and map is what actually runs the rainbow function and preserves its results in the tibble.

The results are provided as a list within a list (a character vector column inside the tibble), so unnest is used to extract them back to a regular vector.

Eventually, to get it as a simple vector you can use answer_tib$rainbow_val.

Please note that the output you provided in the question is inconsistent with the output you should get. It's unclear why maybe you meant to use different values for start_s and start_v?

library(tidyverse)

n_total <- 5
set_alpha <- 0.9
start_s <- 0.7
start_v <- 0.8

answer_tib <- tibble(run_index = seq(0, 0.1, by = 0.1)) %>% 
  mutate(rainbow_val = map(run_index, ~{
    rainbow(n = n_total, start_s - .x, start_v - .x, alpha = set_alpha)
  })) %>% 
  unnest(rainbow_val)

answer_tib$rainbow_val
#>  [1] "#CC3D3DE6" "#AFCC3DE6" "#3DCC76E6" "#3D76CCE6" "#AF3DCCE6" "#B34747E6"
#>  [7] "#9DB347E6" "#47B372E6" "#4772B3E6" "#9D47B3E6"

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 389235

We can use mapply here :

n_total <- 5
grps <- 2
start_s <- 0.7
start_v <- 0.8
Alpha <- 0.9


inds <- seq(0, by = 0.1, length.out = grps)
c(mapply(function(x, y) rainbow(n_total, x, y, alpha = Alpha), 
         start_s - inds, start_v - inds))

#[1] "#B34747E6" "#9DB347E6" "#47B372E6" "#4772B3E6" "#9D47B3E6" 
#    "#994D4DE6" "#8A994DE6" "#4D996BE6" "#4D6B99E6" "#8A4D99E6"

Upvotes: 1

Related Questions