You could use map
to apply the function, then find
to find a mapped value for which _1 == true
, which gives an Option
, and then use getOrElse
to return a default value.
def perform[A, B](list: List[A])(fun: A => (Boolean, B)): (Boolean, B) =
list.map(fun).find(_._1).getOrElse((false, null.asInstanceOf[B]))
The disadvantage is that map
will apply fun
to all elements, whereas you would prefer to abort on the first element for which _1 == true
:
val xs = List(1, 2, 3, 4)
perform(xs) { x =>
println(s"Testing $x")
(x % 2 == 0, x / 2)
}
Testing 1
Testing 2
Testing 3
Testing 4
res0: (Boolean, Int) = (true,1)
One possibility is to use an iterator:
def perform[A, B](list: List[A])(fun: A => (Boolean, B)): (Boolean, B) =
list.iterator.map(fun).find(_._1).getOrElse((false, null.asInstanceOf[B]))
Testing 1
Testing 2
res1: (Boolean, Int) = (true,1)
Also, consider returning an Option[B]
instead of (Boolean, B)
, that way you avoid the ugliness of null
and it's safer to handle on the return side:
def perform[A, B](list: List[A])(fun: A => (Boolean, B)): Option[B] =
list.iterator.map(fun).collectFirst { case (true, res) => res }
Regarding iterator vs view:
I find it always easier to keep track of iterators as long as they offer the methods required. I also think the view mechanism will be reworked in future collections.