pathikrit
pathikrit

Reputation: 33439

Scala: Try till first success on a list

What is the idiomatic way of applying a function A => Try[B] on a List[A] and return either the first succesful result Some[B] (it short-circuits) or if everything fails, returns None

I want to do something like this:

val inputs: List[String] = _

def foo[A, B](input: A): Try[B] = _

def main = {
  for {
   input <- inputs 
  } foo(input) match {
    case Failure(_) => // continue
    case Success(x) => return Some(x) //return the first success
  }
  return None   // everything failed
}

Upvotes: 9

Views: 1865

Answers (3)

Ian
Ian

Reputation: 6104

Here's the same thing but it will return the last Failure in the list if none are successful. Theoretically tries.find(_.isSuccess).getOrElse(tries.last) would work, but on a list view (lazy list) that causes all the attempts to be evaluated twice. Instead, this works for lazy lists (throws on empty collection):

val tries = inputs.view.map(foo)

val firstSuccessOrLastFailure = tries.zipWithIndex.collectFirst({
  case (s @ Success(_), _) => s
  case (f, i) if (i == tries.size - 1) => f
}).get

Upvotes: 0

Michael Zajac
Michael Zajac

Reputation: 55569

You can do the same thing using collectFirst in one less step:

inputs.iterator.map(foo).collectFirst { case Success(x) => x }

Upvotes: 14

Nate
Nate

Reputation: 2205

You want this:

inputs
  .iterator // or view (anything lazy works)
  .map(foo)
  .find(_.isSuccess)
  .map(_.get)

It returns an Option[B].

Upvotes: 8

Related Questions