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

Find the first defined item in a collection in Scala

给定一个集合 coll: C[A] 和一个函数 f: A => Option[B],Scala 中获取 coll 中第一项的惯用方法是什么,其中 f 没有定义评估整个系列?

这是我想要的签名:

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

coll.flatMap(f).headOption 这样天真的方法会评估整个集合。我们可以做 coll.view.flatMap(f).headOptioncoll.collectFirst(Function.unlift(f)) 但是在标准库或函数式编程文献或 scalaz/cats 中是否还有其他东西可以让我这样做?

使用 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))

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
  }

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

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