Scala对列表元素应用函数以返回值

时间:2017-06-20 14:58:57

标签: scala list function

我之前在论坛中找到了一个我一直在寻找的问题的答案,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()将被评估两次。是否有更好的解决方案将函数应用于列表并在满足条件时返回结果(不必遍历所有元素而不必调用函数两次(用于评估和返回值。

2 个答案:

答案 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)