I have a sequence of some objects and I want to collect the first element for which another function returns Some()
For now, my code works this way:
mySeq.collectFirst{
case elem if doSmth(elem).nonEmpty =>
(doSmth(elem).get, elem)
}
Is there a way to:
Refactor it not to call doSmth twice?
change this code to log smth in case doSmth returns None
res.match {
case Some(v) => v
case None => log.info("Searching further...")//partial function doesn't match
}
I would say, the main question is - is it possible to create a PartialFunction that matches all cases, but for some of the cases we do produce some side effect (log message in this case) and explicitly say that it is not matched?
Edit:
I am wondering, why would the following code throw an error when I run tests (not compilation error though)
mySeq.collectFirst{
case elem =>
val r: Option[Int] = doSmth(elem)
r match {
case Some(res) => res
}
}
Yeah, there may be a way to not call doSmth
twice and log the empties, but that would look pretty ugly (you'd have to subclass PartialFunction
explicitly, spell out isDefined
, and have a var
member to keep the result).
Overall, this is just not a good use case for collectFirst
. Just do something like this instead:
mySeq
.view
.map(doSmth)
.flatMap {
case None =>
log("nope")
None
case x => x
}.headOption
Or if you are like me, and prefer a series of short transformations chained together to one monolithic function, here's a fancy way:
mySeq
.view
.map(doSmth)
.map(_.toRight(println("searching")))
.collectFirst { case Right(x) => x }