rerror-handlingtry-catch

Try an expression multiple times until it succeeds in R


I have R code that sometimes returns an NA, which causes errors downstream. However, the only reason that it fails stems from a bad random number. Run the expression again with a different starting point, and it produces results that are not NA.

I've setup a while loop to try the expression multiple times before giving up. Here's an example:

attempts <- 0
x <- NA
while(is.na(x) & attempts < 100) {
     attempts <- attempts + 1
     rand <- runif(1)
     x <- ifelse(rand > 0.3, rand, NA)
}
if(attempts == 100) stop("My R code failed")
x

I don't like how clunky this is.

Is there a function, package, or method that can help simplify this try-repeat-try-again expression?


Solution

  • 1) We could turn it into a function which returns x if it finds one or stops if not. Also we use for instead of while and if instead of ifelse.

    retry <- function() {
      for(i in 1:100) {
        rand <- runif(1)
        x <- if (rand > 0.3) rand else NA
        if (!is.na(x)) return(x)
      }
      stop("x is NA")
    }
    
    retry()
    

    2) or if you don't want the stop in the function then remove the stop line replacing it with a line that returns x and then use this (although it does involve testing x for NA twice):

    x <- retry()
    if (is.na(x)) stop("x is NA")
    

    3) or another option is to pass the bad value to the function. Because of lazy evaluation the bad argument is only evaluated if it is, in fact, bad:

    retry2 <- function(bad) {
      for(i in 1:100) {
        rand <- runif(1)
        x <- if (rand > 0.3) rand else NA
        if (!is.na(x)) return(x)
      }
      bad
    }
    
    retry2(stop("x is NA"))
    

    4) If you don't mind testing x for NA twice using break also works even without a function:

    for(i in 1:100) {
      rand <- runif(1)
      x <- if (rand > 0.3) rand else NA
      if (!is.na(x)) break
    }
    if (is.na(x)) stop("x is NA")
    x