Skip to contents

Provide Python-style "for-else" that works as follows: for each element, execute "for" block, if there is break while executing "for" block, then just stop and ignore the "else" statement, otherwise run "else" block.

Usage

forelse(x, FUN, ALT_FUN = NULL)

Arguments

x

iterative R objects such as list, vector, etc.

FUN

function that applies to each x

ALT_FUN

function that takes no argument or other types of R object

Value

If any FUN returns anything other than NULL, then the function returns the first none NULL object. If all x fed to FUN return NULL, then this function returns ALT_FUN (if ALT_FUN is not a function) or the result of ALT_FUN().

Examples


# --------------------------- Basic Usage ------------------------------

# 1. ALT_FUN get executed because FUN returns NULL for all items in x
forelse(
  1:10,
  function(x){
    cat('The input is ', x, end = '\n')
    if( x > 10) return(x) else return(NULL)
  },
  function(){
    cat('ALT_FUN is executed!\n')
    'wow'
  }
)
#> The input is  1 
#> The input is  2 
#> The input is  3 
#> The input is  4 
#> The input is  5 
#> The input is  6 
#> The input is  7 
#> The input is  8 
#> The input is  9 
#> The input is  10 
#> ALT_FUN is executed!
#> [1] "wow"

# 2. FUN returns non-NULL object
forelse(
  1:10,
  function(x){
    cat('The input is ', x, end = '\n')
    if( x %% 2 == 0 ) return(x) else return(NULL)
  },
  'wow'
)
#> The input is  1 
#> The input is  2 
#> [1] 2

# --------------------------- Performance ------------------------------
FUN <- function(x){
  Sys.sleep(0.01)
  if( x %% 2 == 0 ) return(x) else return(NULL)
}

microbenchmark::microbenchmark({
  forelse(1:10, FUN, 'wow')
}, {
  y <- unlist(lapply(1:10, FUN))
  if(length(y)){
    y <- y[[1]]
  }else{
    y <- 'wow'
  }
}, {
  y <- NULL
  for(x in 1:10){ y <- FUN(x) }
  if(is.null(y)){ y <- 'wow' }
}, times = 3)
#> Unit: milliseconds
#>                                                                                                                       expr
#>                                                                                          {     forelse(1:10, FUN, "wow") }
#>  {     y <- unlist(lapply(1:10, FUN))     if (length(y)) {         y <- y[[1]]     }     else {         y <- "wow"     } }
#>           {     y <- NULL     for (x in 1:10) {         y <- FUN(x)     }     if (is.null(y)) {         y <- "wow"     } }
#>        min        lq      mean    median        uq      max neval
#>   20.20369  20.22231  20.25704  20.24092  20.28371  20.3265     3
#>  100.79285 100.95658 101.01362 101.12032 101.12400 101.1277     3
#>  100.71799 100.90208 100.96520 101.08616 101.08881 101.0915     3