Sean Norton
Sean Norton

Reputation: 287

Using tryCatch to skip execution upon error without exiting lapply()

I am trying to write a function that cleans spreadsheets. However, some of the spreadsheets are corrupted and will not open. I want the function to recognize this, print an error message, and skip execution of the rest of the function (since I am using lapply() to iterate across files), and continues. My current attempt looks like this:

candidate.cleaner <- function(filename){

  #this function cleans candidate data spreadsheets into an R dataframe

  #dependency check
  library(readxl)

  #read in

    cand_df <-  tryCatch(read_xls(filename, col_names = F),
    error = function (e){
            warning(paste(filename, "cannot be opened; corrupted or does not exist"))
    })
  print(filename)

  #rest of function

  cand_df[1,1]

}

test_vec <- c("test.xls", "test2.xls", "test3.xls")
lapply(FUN = candidate.cleaner, X = test_vec)

However, this still executes the line of the function after the tryCatch statement when given a .xls file that does not exist, which throws a stop since I'm attempting to index a dataframe that doesn't exist. This exits the lapply call. How can I write the tryCatch call to make it skip execution of the rest of the function without exiting lapply?

Upvotes: 1

Views: 94

Answers (2)

Martin Morgan
Martin Morgan

Reputation: 46866

One could set a semaphore at the start of the tryCatch() indicating that things have gone OK so far, then handle the error and signal that things have gone wrong, and finally check the semaphore and return from the function with an appropriate value.

lapply(1:5, function(i) {
    value <- tryCatch({
        OK <- TRUE
        if (i == 2)
            stop("stopping...")
        i
    }, error = function(e) {
        warning("oops: ", conditionMessage(e))
        OK <<- FALSE                    # assign in parent environment
    }, finally = {
        ## return NA on error
        OK || return(NA)
    })
    ## proceed
    value * value
})

This allows one to continue using the tryCatch() infrastructure, e.g., to translate warnings into errors. The tryCatch() block encapsulates all the relevant code.

Upvotes: 1

Sean Norton
Sean Norton

Reputation: 287

Turns out, this can be accomplished in a simple way with try() and an additional help function.

candidate.cleaner <- function(filename){

  #this function cleans candidate data spreadsheets into an R dataframe

  #dependency check
  library(readxl)

  #read in
  cand_df <- try(read_xls(filename, col_names = F))
  if(is.error(cand_df) == T){
  return(list("Corrupted: rescrape", filename))
  } else {
  #storing election name for later matching
  election_name <- cand_df[1,1]
}
}

Where is.error() is taken from Hadley Wickham's Advanced R chapter on debugging. It's defined as:

is.error <- function(x) inherits(x, "try-error")

Upvotes: 1

Related Questions