Home > Software engineering >  How to conditionally change the iterator value in for loop?
How to conditionally change the iterator value in for loop?

Time:10-14

I created the following example in an attempt to clarify my question. ranPick draws a random number for each iteration but if it draws a negative number the next two places are also assigned the same number as ranPick[i].

The following DOES NOT return what I intended. It counts the i globally it seems and override the manual attempt i <- i 3.

I know that I can use while loop or different index other than i. But I am wondering if it is possible to tell this for loop to jump over some iterations conditionally?

ranPick <- numeric()
for (i in 1:100){
  ranPick[i] <- (round(rnorm(1, 1, 5)))
  if (ranPick[i] < 0){
    ranPick[i:(i 2)] <- ranPick[i]
    i <- i   3
  }
}

CodePudding user response:

In general, next tells a for-loop to skip TO the next iteration. I dont think there is a way to tell a for loop to skip THE next iteration(s) hence this workaround might be the way to go.

You define a counter variable that is filled with the number of iterations to skip if a specific case happens, e.g. sample value < 0. At the beginning of each iteration this counter vriable is checked whether the iteration should be skipped. If so, 1 is substracted from the counter and the iteration is skipped by using the keyword next.

set.seed(123)

# assign vetor of desired length
len <- 10
ranPick <- numeric(len)

# use counter 
skip_count <- 0
for (i in seq_len(len)){
  
  # skip if already filled and counter is != 0
  if (skip_count != 0) {
    # reduce counter by 1 to indicate an iteration was skipped
    skip_count <- skip_count - 1
    print("skip")
    next
  }
  ranPick[i] <- (round(rnorm(1, 1, 5)))
  if (ranPick[i] < 0){
    print("<0")
    
    # min ensures the vector length does not exceed the desired length
    ranPick[i:min(i 2, len)] <- ranPick[i]

    # set counter to desired iterations to skip
    skip_count <- 2
  }
}
#> [1] "<0"
#> [1] "skip"
#> [1] "skip"
#> [1] "<0"

ranPick
#>  [1] -2 -2 -2  0  9  1  2 10  3 -5

Note that I added a min() call to ensure the outcome vector is not longer than the desired number of iterations. In this example, iteration 10 produces a negative number and hence -5 would be added 3 times, resulting in a vector of length 12.

CodePudding user response:

As mentioned by Robert Hacken and mnist, you can't control the behavior of the index variable at the beginning of each loop.

A few options for the example problem:

lranPick <- vector("list", 3)
set.seed(1167952300)
ranPick <- numeric(100)
skip <- 0L
for (i in 1:100){
  if (skip) {
    skip <- skip - 1L
  } else {
    ranPick[i] <- round(rnorm(1, 1, 5))
    if (ranPick[i] < 0){
      ranPick[i:(i 2)] <- ranPick[i]
      skip <- 2L
    }
  }
}
lranPick[[1]] <- ranPick[1:100]

set.seed(1167952300)
ranPick <- numeric(100)
skip <- 0L
for (i in 1:100){
  if (skip) {
    skip <- skip - 1L
    ranPick[i] <- ranPick[i - 1L]
  } else {
    ranPick[i] <- round(rnorm(1, 1, 5))
    skip <- 2L*(ranPick[i] < 0)
  }
}
lranPick[[2]] <- ranPick

set.seed(1167952300)
ranPick <- round(rnorm(100, 1, 5))
lranPick[[3]] <- rep.int(ranPick, 1L   2L*(ranPick < 0))[1:100]

identical(lranPick[-1], lranPick[-3])
#> [1] TRUE
  • Related