给定一个集合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).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中还有其他东西可以让我这样做吗?
答案 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))