Reputation: 33439
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
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
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
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