3

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!!

2
  • Note your assignment of tmpVar in the tryCatch is local to the function. Thus it has no effect on the value of tmpVar. Commented Mar 13, 2019 at 7:25
  • @Hugh Thanks, I do understand that is the issue, how do I push it up into the environment of the for loop? Commented Mar 13, 2019 at 7:38

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

13 Comments

Thanks Tim, but now my output is only: [1] "foo" "1" for x
@ Tim Biegeleisen that's giving the same result: [1] "foo" "1" --sorry, don't have the hang of this formatting yet!
I fixed it. Sorry for the confusion.
That's awesome, and thanks for sharing the reason for the behavior. Only one little detail: the message/row is hardcoded. I added a different error for 4 if (e == 4) stop("FOUR?") and substituted the d in for the return and it blew up again. How do I pass that argument?
I updated the question to reflect this (I hope that's the right thing to do).
|
1

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!>

3 Comments

@ A. Suliman Awesome, that works. Thank you! Getting warmer... I'm not sure I understand your "PS" about extracting the d. Would you mind elaborating? (The actual error will be a "404" or similar returned from an API call, if that helps…)
@Old_Newb see my update. Let me know if you need more elaborate.
This is a great alternative and thorough explanation. Thank you! Wish I could select two answers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.