简体   繁体   中英

Scala apply function on list elements to return a value

I have found this answer in the forum earlier to a question I have been looking for, How to find a matching element in a list and map it in as an Scala API method?

// Returns Some(66)
List(1, 2, 3) collectFirst { case i if (i * 33 % 2 == 0) => i * 33 }

Now if I am replacing the if clause with a function

// 
List(1, 2, 3) collectFirst { case i if ( test(i) > 0) => test(i) }

this works but test() will be evaluated twice. Is there a better solution to apply a function to a list and return a result when a condition is met (not having to go through all elements and not havong to call the function twice (for evaluation and for returning the value.

Something like this, perhaps? Breaking it into two separate operations lets you save/reuse intermediate results.

List(1,2,3).iterator.map(test).find(_ > 0)

You can wrap your function in a custom extractor:

def test(i: Int): Int = i - 1

object Test {
  def unapply(i: Int): Option[Int] = Some(test(i))
}

scala> List(1, 10, 20) collectFirst { case Test(i) if i > 0 => i }
res0: Option[Int] = Some(9)

You can generalize this solution and make a class for that kind of extractors:

case class Extract[T, U](f: T => U) {
  def unapply(t: T): Option[U] = Some(f(t))
}

scala> val Test2 = Extract(test)
Test2: Extract[Int,Int] = Extract($$Lambda$1326/1843609566@69c33ea2)

scala> List(1, 10, 20) collectFirst { case Test2(i) if i > 0 => i }
res1: Option[Int] = Some(9)

You can also wrap the guard into the extractor as well:

case class ExtractWithGuard[T, U](f: T => U)(pred: U => Boolean) {
  def unapply(t: T): Option[U] = {
    val u = f(t)
    if (pred(u)) Some(u)
    else None
  }
}

scala> val Test3 = ExtractWithGuard(test)(_ > 0)
Test3: ExtractWithGuard[Int,Int] = ExtractWithGuard($$Lambda$1327/391731126@591a4d25)

scala> List(1, 10, 20) collectFirst { case Test3(i) => i }
res2: Option[Int] = Some(9)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM