取消已选择的选项化期权

41

假设我有一个val s: Option[Option[String]]。它可能会有以下几种值:

Some(Some("foo")) Some(None) None

我想将其简化,使第一个变为Some("foo"),而其他两个变为None。显然,有很多方法可以实现这一点,但我正在寻找一个简单的、内置的、不到一行代码的方法。

6个回答

38

很遗憾flatten不存在。它应该存在。

现在flatten已经存在了。

与以前一样,

s getOrElse None
< p >(除了其他答案之外)也会做同样的事情。


5
看起来现在存在: scala> Some(Some(1)).flatten res10: Option[Int] = Some(1) - Alexy
似乎“flatten”也已经成为了Cats库中的一部分。请参见:https://non.github.io/cats//tut/monad.html - StuartLC
@Alexy 当我对像 Some(Some(Some(1))) 这样的对象调用 flatten 时,我会得到 Cannot prove that Any <:< Option[B] 的错误提示。 - bachr

16

你可以使用scalazjoin函数来实现,因为这是一个单子操作

doubleOpt.join

在 REPL 中,它是这样的:

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> some(some("X")).join
res0: Option[java.lang.String] = Some(X)

scala> some(none[String]).join
res1: Option[String] = None

scala> none[Option[String]].join
res3: Option[String] = None

任何拥有Monad类型类实例的对象都可以使用它。


我有一个类似于val map = Map("a"->Some(Some(1)), "b"->2)的映射,当我调用map.get("a").join时,我看到了could not find implicit value for parameter ev: scalaz.Liskov.<~<[Any,Option[B]]的错误提示。 - bachr

14
s.flatten

紧随其后的一堆字符,以使我达到stackoverflow允许的最低要求


1
这正是我所考虑的,但它返回一个Iterable而不是Option。 - Knut Arne Vedaa
6
嗯,这非常奇怪。他们为什么要这样做?尝试使用s.flatmap(x=>x)代替。 - Dave Griffith
7
可以使用s flatMap identity来表示。 - Frank S. Thomas
2
总结以上内容:List(Some(Some("foo")), Some(None), None) map { _ flatMap identity } 产生 List[Option[java.lang.String]] = List(Some(foo), None, None),这就是我认为 Knut(楼主和我听说过的第一个非北极熊崽子名叫“Knut”)想要的。 - Michael Lorton

4

我认为将其转换为可迭代对象是可行的。按照以下步骤,从Option[Option[String]转换为单个Option[String]

s.flatten.headOption 

(返回Option[String]的值)

1
您可以像以下这样使用flatMap:
val options = List(Some(Some(1)), Some(None), None)
options map (_ flatMap (a => a))

这将把 List [Option [Option [Int]]] 映射到 List [Option [Int]]
如果你只有一个 Option,你可以按照以下方式使用它:

val option = Some(Some(2))
val unzippedOption = option flatMap (b => b)

这将把你的 Option[Option[Int]] 扁平化为 Option[Int]

-4

嗯,我其实不明白为什么它可能只是None(第三种情况)。如果它确实也可能只是None,那么我会投票支持Rex Kerr的答案,否则只用.get就足够了:

scala> Some(Some("foo")).get
res0: Some[java.lang.String] = Some(foo)

scala> Some(None).get
res1: None.type = None

它可以是None,因为它是一个Option - oxbow_lakes
是的,但这是Option内部的Option...所以我期望正面结果是Some(Some("something")),负面结果是Some(None)。那么第三种状态描述的只是None吗?如果问题在于三态逻辑,那么这才有意义。 - Antonin Brettsnajdr
3
这句话的意思是:它有点相当于一个未来:Some(Some(X)) 是一个计算出的值,Some(None) 表示未来已经完成但没有任何值,None 表示未来尚未返回。 - oxbow_lakes
1
Option[String] 是一个字符串或者不是。我们可以将其表示为 String + 1,意思是它可以是任何字符串或另一种东西。那么 Option[Option[String]] 就是 (String + 1) + 1,或者 String + 2。也就是说,它要么是一个字符串,要么是另外两种东西之一。换句话说,Option[Option[String]] 等同于 Either[Boolean, String]。我认为后面的结构更清晰地表明了它要么成功生成一个字符串,要么以两种不同的方式失败。 - James Iry
1
哈哈,很好的解释--“失败有很多种方式,而成功只有一种。” :-) - Antonin Brettsnajdr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接