我之前在论坛中找到了一个我一直在寻找的问题的答案,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 }
现在,如果我用函数
替换if子句//
List(1, 2, 3) collectFirst { case i if ( test(i) > 0) => test(i) }
这可行,但test()将被评估两次。是否有更好的解决方案将函数应用于列表并在满足条件时返回结果(不必遍历所有元素而不必调用函数两次(用于评估和返回值。
答案 0 :(得分:2)
也许这样的事情? 将其分为两个单独的操作,可以保存/重用中间结果。
List(1,2,3).iterator.map(test).find(_ > 0)
答案 1 :(得分:1)
您可以将函数包装在自定义提取器中:
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)
您可以推广此解决方案并为这种提取器创建一个类:
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)
你也可以将守卫包裹在提取器中:
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)