Reputation: 327
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
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
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
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