我正在尝试折叠选项列表,以便返回第一个(或最后一个)某些值,如果没有任何某些值则返回None。
scala> val opts = List(None, Some(1), None, Some(2), None)
opts: List[Option[Int]] = List(None, Some(1), None, Some(2), None)
scala> opts foldLeft(None)((a,io) => a match { case None => io; case Some(i) =>
a})
<console>:9: error: object None does not take parameters
opts foldLeft(None)((a,io) => a match { case None => io; case Some
(i) => a})
^
不确定我做错了什么。也许有一种方法可以使用更高阶函数来简化这一操作,但here没有任何内容引起我的注意。
答案 0 :(得分:14)
也许这可以解决您的问题 - 第一个要素:
opts.flatten.headOption
最后一个元素:
opts.flatten.lastOption
flatten
方法将取消列出列表中的所有Option
值并删除所有None
值。对于列表中的第一个/最后一个元素,headOption
/ lastOption
将返回Some
,如果列表为空,则返回None
。
答案 1 :(得分:9)
tenshi’s answer非常简单,但对于长列表,它会尝试压扁所有内容,因为它不是懒惰的。 (我认为view
也不会帮助我们,但我不太确定。)
在这种情况下,您可以使用:
opts.dropWhile(_.isEmpty).headOption.flatMap(identity)
很遗憾,我们无法在此处使用flatten
,因为这会返回通用Iterable[Int]
而不是Option
,因此我们必须选择较长的成语flatMap(identity)
。
修改:dave注意到:
opts.find(_.isDefined).flatMap(identity)
会更好。
答案 2 :(得分:4)
有更好的方法可以做到,但要回答提出的问题,你有两个问题
1)您错过了.
之后的opts
。您只能使用中缀表示法将a.m(b)
转换为a m b
。 foldLeft方法的格式为a.m(b)(c)
。所以要么像那样写,要么包括括号(a m b)(c)
。
2)您需要将None
参数化为Option[Int]
:它在此被解释为None
对象,而不是Option[Int]
的值实例
所以这会奏效:
opts.foldLeft(None: Option[Int])(
(a,io) => a match { case None => io; case Some(i) => a } )
答案 3 :(得分:2)
为什么会遇到这样的麻烦?
opts.find(_.nonEmpty).flatten
opts.reverse.find(_.nonEmpty).flatten
答案 4 :(得分:0)
从Scala 2.9
开始,您可以使用collectFirst
提取第一个定义的选项:
List(None, Some(1), None, Some(2), None).collectFirst { case Some(x) => x }
// Option[Int] = Some(1)
这将在第一个定义的Option
处停止迭代,并避免在寻找其头部之前弄平整个List
。
从Scala 2.13
开始,您可以使用findLast
,它与find
的相反(在等待可能的collectLast
吗?)
List(None, Some(1), None, Some(2), None).findLast(_.isDefined).flatten
// Option[Int] = Some(2)