简体   繁体   中英

R use tryCatch within for loop to add row with error values to output

forgive me if I missed the right way to do this here, but I can't seem to make progress. Skipping error in for-loop helped a lot, as did some of the other answers related to tryCatch, but I'm still struggling. using tryCatch() in R to assign error values in loop didn't work for me, or I'm missing something.

I am running a for loop with tryCatch, but if I get an error, I would like to record it as a row in the resulting matrix. I can't seem to get the error function output up one level to the loop to be recorded. Here is a simple version of what I'm trying:

collectem <- function(eList){ 
  tmpList <- NULL
  for (e in eList){
    tryCatch({
    tmpVar <- c("foo", e)
    if (e==3) stop("BLAH!")
    }, error=function(d){c("No",d) -> tmpVar})
    tmpList <- rbind(tmpList, tmpVar)
  }
  return(tmpList)
}

Call:

x <- collectem(1:10)

Which results in:

> x
       [,1]  [,2]
tmpVar "foo" "1" 
tmpVar "foo" "2" 
tmpVar "foo" "3" 
tmpVar "foo" "4" 
tmpVar "foo" "5" 
tmpVar "foo" "6" 
tmpVar "foo" "7" 
tmpVar "foo" "8" 
tmpVar "foo" "9" 
tmpVar "foo" "10"

But I'm looking for this:

x
       [,1]  [,2]   
tmpVar "foo" "1"    
tmpVar "foo" "2"    
tmpVar "No"  "BLAH!"
tmpVar "foo" "4"    
tmpVar "foo" "5"    
tmpVar "foo" "6"    
tmpVar "foo" "7"    
tmpVar "foo" "8"    
tmpVar "foo" "9"    
tmpVar "foo" "10"   

Thanks!!

You may use the pattern of returning whatever tuple you want from the error and/or warning handler functions of tryCatch :

collectem <- function(eList) { 
    tmpList <- NULL
    for (e in eList) {
        tmpVar <- tryCatch(
            {
                if (e == 3) stop("**BLAH!**")
                c("foo", e)
            },
            error = function(d) {
                return(c("No", sub(".*\\*\\*(.*?)\\*\\*.*", "\\1", d)))
            }
        )
                print(tmpVar)
        tmpList <- rbind(tmpList, tmpVar)
    }
    return(tmpList)
}

eList <- c(1:10)
collectem(eList)

       [,1]  [,2]   
tmpVar "foo" "1"    
tmpVar "foo" "2"    
tmpVar "No"  "BLAH!"
tmpVar "foo" "4"    
tmpVar "foo" "5"    
tmpVar "foo" "6"    
tmpVar "foo" "7"    
tmpVar "foo" "8"    
tmpVar "foo" "9"    
tmpVar "foo" "10"

What I learned here is that tryCatch indeed returns a value when calling it. However, the value returned for the try block is just the implicit statement which executes. Calling return from the try block will cause the entire function to return, which is not what we want. On the other hand, we can (and arguably should) use an explicit return for the error and warning blocks. In this case, the return just returns from the call to tryCatch , and not from the entire enclosing function.

Here a pattern using try

collectem <- function(eList){ 
  #browser()
  tmpList <- NULL
  for (e in eList){
      flag <- try(if (e==3) stop("BLAH!"),silent = TRUE)
      if(!is.null(flag) && class(flag)=="try-error"){
        #tmpVar <- c("No","BLAH!")  
        d <- gsub('.*\\: (.*)\n','\\1',flag)
        tmpVar <- c("No",d)  
      } else {tmpVar <- c("foo", e)}

    tmpList <- rbind(tmpList, tmpVar)
  }
  return(tmpList)
}

When we hit e=3 flag will be

flag
[1] "Error in try(if (e == 3) stop(\"BLAH!\"), silent = TRUE) : BLAH!\n"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in doTryCatch(return(expr), name, parentenv, handler): BLAH!>

So we can extract anything after : and before \\n as the Error message using gsub and grouping. Here what we will get

gsub('.*\\: (.*)\n','\\1',flag)
[1] "BLAH!"
attr(,"class")
[1] "try-error"
attr(,"condition")
<simpleError in doTryCatch(return(expr), name, parentenv, handler): BLAH!>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM