Search code examples
scalacollectpartialfunction

partialFunction in collectFirst


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:

  1. Refactor it not to call doSmth twice?

  2. 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
  }
}

Solution

  • 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 }