是否有一种方法可以不使用find
和map
两种方法来完成以下操作?
val l = 0 to 3
l.find(_ * 33 % 2 == 0).map(_ * 33) // returns Some(66)
使用collect如何?
// Returns List(66)
List(1, 2, 3) collect { case i if (i * 33 % 2 == 0) => i * 33 }
不过那会返回所有匹配项而不仅仅是第一个。
更好的答案应该基于Scala 2.9:
// Returns Some(66)
List(1, 2, 3) collectFirst { case i if (i * 33 % 2 == 0) => i * 33 }
评论中提出的解决方案是追加head
以获取Scala 2.8版本,但恐怕效率不高。也许在这种情况下,您应该坚持使用自己的代码。无论如何,为了确保它返回一个选项,您不应该调用head
,而应该调用headOption
。
// Returns Some(66)
List(1, 2, 3) collect { case i if (i * 33 % 2 == 0) => i * 33 } headOption
collect
会返回多个匹配项,而 find
只返回一个。 - Daniel C. SobralcollectFirst
方法。如果不使用collectFirst
,就需要同时使用headOption
和collect
来获得与原始示例相同的类型和行为,这也是达尼尔评论所暗示的。 - Kristian Domagalaguard
的中间结果。 - lisaki*33
两次。有没有可能只计算一次? - vvgmap()
操作(例如如果它是一个昂贵的数据库查找),您可以这样做:
l.view.map(_ * 33).find(_ % 2 == 0)
view
使集合变成懒加载,因此最小化了map()
操作的数量。嘿,看这里,我的小伙伴findMap
又出现了!
/**
* Finds the first element in the list that satisfies the partial function, then
* maps it through the function.
*/
def findMap[A,B](in: Traversable[A])(f: PartialFunction[A,B]): Option[B] = {
in.find(f.isDefinedAt(_)).map(f(_))
}
collectFirst
方法相似,这个代码会在找到匹配元素后立即停止。Traversable
已经定义了 collectFirst
方法,该方法与您的 findMap
所做的完全相同。 - Simão Martins这个可以做到,但如果你能告诉我你真正想要实现什么,那会更容易些:
l.flatMap(n => if (n * 33 % 2 == 0) Some(n * 33) else None).headOption