Greg
Greg

Reputation: 11542

Can I store an intermediate result in an Scala case match?

Say I have this:

def expensiveTest(t: String): Option[Int] = {...}
// myList: List[String]
myList.collectFirst {
  case x if expensiveTest(x).isDefined => expensiveTest(x).get
}

Something like this works, but... I have to call expensiveTest() twice. Is there a way to save the result of the guard's call to expensiveTest to use on the right side of the =>?

Upvotes: 3

Views: 128

Answers (3)

curious
curious

Reputation: 2928

Xavier's solution is good but it will fail if myList is empty. Another alternative approach is simply using tail recursion:

import scala.annotation.tailrec
  val l = List(1,2,3,4,5)
  def expensiveTest(t: Int): Option[Int] = if(t % 2 == 0) Some(t) else None
  @tailrec
  def f(l: List[Int]): Option[Int] = {
    l match {
      case Nil => None
      case h :: t => expensiveTest(h) match {
        case None => f(t)
        case x => x
      }
    }
  }

scala> f(l)
res0: Option[Int] = Some(2)

Upvotes: 0

Xavier Guihot
Xavier Guihot

Reputation: 61774

Switching the List to a lazy Stream and using a map/head could be an alternative:

myList.toStream.flatMap { case x => expensiveTest(x) }.head

Upvotes: 3

Nagarjuna Pamu
Nagarjuna Pamu

Reputation: 14825

Yes, There is a way to do. We can use extractor pattern

object ExpensiveTest {
  unapply(x: String): Option[String] = if (x.isEmpty) None else Some(x) // Some logic
}

myList.collectFirst {
  case ExpensiveTest(nonEmptyString) => nonEmptyString
}

Upvotes: 1

Related Questions