I'm trying to manually increment the i variable when a condition is met.
for(i in 1:x){
if(condition){
i <- i + 2
}
}
When debugging, the (i<-i+2) line is definitely being run, but i still only increments by 1, instead of 3. (+2 from the line and an additional +1 from the auto increment)
How can I increment while I'm within the loop?
So essentially you want to skip a few loop iterations based on a condition. It's a design choice that's rightfully frowned upon, but if you must, you need next. The following code skips the third, fifth and seventh iteration:
for(i in 1:10){
if(i %in% c(3,5,7)){
next
}
print(i)
}
Say you need to increment with 3 based on a certain condition, then you can use a temporary variable that helps you skip a number of steps. Note that this does go through every iteration, it just breaks out of the iteration in time:
skip <- 0 # the temporary variable helping us keeping track of the iterations
for(i in 1:10){
if(i == 5){ # the condition that causes the skip
skip <- 3
}
if(skip > 0){ # the control that skips as long as necessary
skip <- skip - 1
next
}
print(i)
}
When you run the loop, the value of the variable i is stored in tmp*. This means that whenever we reach the top the loop, i resets. For example
for(i in 1:2){
message(i)
i <- 10
message(i)
}
#1
#10
#2
#10
To get what you want, you could have something like:
k =1
for(i in 1:10){
if(condition) k <- k + 2
}
Once the sequence is created, you pretty much lose a lot of control over looping. In cases like this, I change it into a while loop and then do the conditional incrementing/decrementing at the end of the loop.
I'm agree with joris-meys, it's "frowned upon". But... A more simple approach is:
for(i in (0:3)*2+1){
cat(i," ")
}
or
for(i in (1:4)){
cat(i," ")
}
for(i in seq(0, 10, 2) ){
print(i)
}
you can do this..
Related
I'm trying to save each iteration of this for loop in a vector.
for (i in 1:177) {
a <- geomean(er1$CW[1:i])
}
Basically, I have a list of 177 values and I'd like the script to find the cumulative geometric mean of the list going one by one. Right now it will only give me the final value, it won't save each loop iteration as a separate value in a list or vector.
The reason your code does not work is that the object ais overwritten in each iteration. The following code for instance does what precisely what you desire:
a <- c()
for(i in 1:177){
a[i] <- geomean(er1$CW[1:i])
}
Alternatively, this would work as well:
for(i in 1:177){
if(i != 1){
a <- rbind(a, geomean(er1$CW[1:i]))
}
if(i == 1){
a <- geomean(er1$CW[1:i])
}
}
I started down a similar path with rbind as #nate_edwinton did, but couldn't figure it out. I did however come up with something effective. Hmmmm, geo_mean. Cool. Coerce back to a list.
MyNums <- data.frame(x=(1:177))
a <- data.frame(x=integer())
for(i in 1:177){
a[i,1] <- geomean(MyNums$x[1:i])
}
a<-as.list(a)
you can try to define the variable that can save the result first
b <- c()
for (i in 1:177) {
a <- geomean(er1$CW[1:i])
b <- c(b,a)
}
I would like to skip iterations in a for loop based on conditions. Intuitively I thought this would work:
for(i in 1:10){
if(i %in% c(1,2,3,4,5)){
print(i)
i <- i+2}
}
I would want it to return
1
4
but instead it returns
1
2
3
4
5
I am aware why this is happening.
Is there another way to skip (multiple) iterations based on a condition in a for loop in R?
It's not just bad practice to increment the counter inside the loop in R. It simply will not work. That's not the way the language is built. If you want to get 1 and 4 printed then try:
for(i in seq(1,10,by=3) ){
if(i %in% c(1,2,3,4,5)){
print(i)
}
}
Do also note that for-loops actually return NULL. There would be a side-effect of printing to the console, but no values of variables would change. If you want values to change you need to do assignment inside the loop.
The is a next control statement:
for(i in seq(1,10) ){
if( !(i %in% c(1,4)) ){ next }
print(i)
}
I'd like to iterate through a list of items and get the current iteration number. is there an easy way do this?
This is my (example) loop:
loopit <- c('happ','goof','funk')
str <- ''
for (l in loopit){
print(paste0(l,'y'))
}
It's easy to build an iteration counter manually:
i <- 1
for (l in loopit){
if(i==1){
print(paste0('so ',l,'y!!!'))
}else{
print(paste0(l,'y'))
}
i <- i + 1
}
Is there a more elegant, more direct way to get the current iteration number?
For this specific example you do not necessary need to know the number of iteration. Maybe it is the same also for your real problem. See the example.
foo <- function(x) {
print(paste0('so ', head(x, 1), 'y!!!'))
for (l in tail(x, -1)) print(paste0(l, 'y'))
}
foo(loopit)
I would like to have 2 sets of Sys.sleep. One long one and very short at each iteration. The current example does the first "long sleep" however doesn't proceed with the next one.
Here is example:
out <- as.numeric()
for(i in 1:20){
out[i] <- i*5
if(i==seq(5,20,5)){
Sys.sleep(5); print("Long sleep")
} else {
for(j in 1:5){
Sys.sleep(0.15); cat(j)
}}}
out
The loop should have a "Long sleep" with 5sec at each 5th iteration and 0.15sec at each iteration.
What I'm doing wrong here? Thanks.
The error the condition has length > 1 and only the first element will be used should have been an indicator that your if test was incorrect. Let's try it on the console:
i <- 5
i == seq(5,20,5)
## [1] TRUE FALSE FALSE FALSE
When you do that in an if statement, it is expecting one and only one logical out of the comparison, so it is rightfully confused. (Which would you use?)
Perhaps you meant i %in% seq(5,20,5)? Even better, I suggest you pre-assign the sequence and compare against it, otherwise you are creating a static vector every time.
myseq <- seq(5,20,5)
for(i in 1:20) {
out[i] <- i*5
if(i %in% myseq) {
Sys.sleep(5); print("Long sleep")
} else {
for(j in 1:5) {
Sys.sleep(0.15); cat(j)
}
}
}
As an alternative, you could also check (i %% 5 == 0), which can be faster, depending on the size of your test sequence.
I have a command that generates a variable every 10 loops in R (index1, index2, index3... and so on). The command I have is functional, but I am thinking of a smarter way to write this command. Here's what my command looks like:
for (counter in 1:10){
for (i in 1:100){
if (counter == 1){
index1 <- data1 ## some really long command here, I just changed it to this simple command to illustrate the idea
}
if (counter == 2){
index2 <- data2
}
.
.
.
# until I reach index10
} indexing closure
} ## counter closure
Is there a way to write this without having to write the conditional if commands? I would like to generate index1, index2.... I am sure there is some easy way to do this but I just cannot think of it.
Thanks.
What you need is the modulo operator %%. inside the inner loop. Ex: 100%%10 returns 0 101%%10 returns 1 92%%10 returns 2 - in other words if it is multiple of 10 then you get 0. And the assign function.
Note: You no longer need the outer loop used in your example.
So to create a variable at every 10 iteration do something like this
for(i in 1:100){
#check if i is multiple of 10
if(i%%10==0){
myVar<-log(i)
assign(paste("index",i/10,sep=""), myVar)
}
}
ls() #shows that index1, index2, ...index10 objects have been created.
index1 #returns 2.302585
update:
Alternatively, you can store results in a vector
index<-vector(length=10)
for(i in 1:100){
#check if i is multiple of 10
if(i%%10==0){
index[i/10]<-log(i)
}
}
index #returns a vector with 10 elements, each a result at end of an iteration that is a multiple of 10.