在Scala中查找集合中的第一个定义项

时间:2016-10-02 15:51:06

标签: scala functional-programming scalaz flatmap scala-cats

给定一个集合coll: C[A]和一个函数f: A => Option[B],Scala中用于获取collfdef findFirstDefined[A, B](coll: Traversable[A])(f: A => Option[B]): Option[B] 的第一个项目的惯用方法是什么?在没有评估整个集合的情况下进行定义?

这是我的预期签名:

coll.flatMap(f).headOption

coll.view.flatMap(f).headOption这样天真的方法会评估整个集合。我们可能会coll.collectFirst(Function.unlift(f))<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <argLine>-Xmx1024M ${argLine}</argLine> </configuration> </plugin> 但是在标准库或函数式编程文献中还是scalaz / cats中还有其他东西可以让我这样做吗?

3 个答案:

答案 0 :(得分:2)

如果您想使用标准的东西,IMO coll.collectFirst(Function.unlift(f))看起来是一个很好的解决方案。但是使用递归很容易实现:

@annotation.tailrec
def findFirstDefined[A, B](coll: Traversable[A])(f: A => Option[B]): Option[B] =
  if (coll.isEmpty) None
  else {
    val r = f(coll.head)
    if (r.isEmpty) findFirstDefined(coll.tail)(f)
    else r
  }

答案 1 :(得分:0)

如何使用find(p: A => Boolean)

def findFirstDefined[A, B](coll: Traversable[A])(f: A => Option[B]): Option[B] =
    coll.find(f(_).isDefined).flatMap(f(_))

这需要两次调用f.apply(),但只会调用apply(),直到找到返回已定义选项的第一个元素。

编辑:考虑一下(但是Victor击败了我),collectFirst()也是一个更优雅的选择:

coll.collectFirst(Function.unlift(f))

答案 2 :(得分:0)

正如问题所述,这似乎是一个不错的解决方案:

def findFirstDefined[A, B](coll: Traversable[A])(f: A => Option[B]): Option[B] = 
  coll.collectFirst(Function.unlift(f))