1

给定一个集合coll: C[A]和一个函数,Scala 中的惯用方式是在不评估整个集合的情况下获取定义的f: A => Option[B]第一项?collf

这是我的预期签名:

def 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))在标准库、函数式编程文献或 scalaz/cats 中还有其他东西可以让我这样做吗?

4

3 回答 3

2

如果您想使用标准的东西, IMOcoll.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
  }
于 2016-10-02T16:56:45.337 回答
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()直到找到返回定义选项的第一个元素。

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

coll.collectFirst(Function.unlift(f))
于 2016-10-02T16:41:00.500 回答
0

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

def findFirstDefined[A, B](coll: Traversable[A])(f: A => Option[B]): Option[B] = 
  coll.collectFirst(Function.unlift(f))
于 2016-10-07T14:34:12.270 回答