Search code examples
rlapplybreak

Equivalent "break" for the lapply function


I am trying to make a function that will terminate conditionally. Let this condition be "if (i == 5)"

le <- letters
for(i in seq_along(let)){
   ## some code
  print(le[i])
  if(i==5) break
}

with for everything goes well

[1] "a"
[1] "b"
[1] "c"
[1] "d"
[1] "e"

but when I use lapply I get an error

fu <- function(i){
  ## some code
  print(le[i])
  if(i==5) break
} 
lapply(1:length(le) , fu)

res

[1] "a"
[1] "b"
[1] "c"
[1] "d"
[1] "e"
Error in FUN(X[[i]], ...) : no loop for break/next, jumping to top level
Called from: FUN(X[[i]], ...)

How do I fix it?


Solution

  • You can't fix it, and there aren't any simple workarounds. lapply() doesn't support break. If you want break, you need to use a different kind of loop.

    Here's one workaround:

    le <- letters
    
    fu <- local({
      broken <- FALSE
      function(i){
        if (broken) return()
        ## some code
        print(le[i])
        if(i==5) broken <<- TRUE
      }
    })
    
    res <- lapply(1:length(le) , fu)
    #> [1] "a"
    #> [1] "b"
    #> [1] "c"
    #> [1] "d"
    #> [1] "e"
    

    Created on 2021-09-05 by the reprex package (v2.0.0)

    If you look at res, you'll see that it contains 21 NULLs, because it is still called 26 times. You can't stop that without very dangerous messing around in lapply() internal variables.