【问题标题】:Un-optioning an optioned Option取消选择选项
【发布时间】:2011-08-23 12:36:07
【问题描述】:

假设我有一个val s: Option[Option[String]]。因此它可以具有以下值:

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

我想减少它,使第一个变成Some("foo"),而另外两个变成None。显然有很多方法可以实现这一点,但我正在寻找一种简单的、可能是内置的、少于一个衬里的方法。

【问题讨论】:

    标签: scala join option monads flatten


    【解决方案1】:
    s.flatten
    

    后面跟着一堆字符,让我达到 stackoverflow 允许的最低限度

    【讨论】:

    • 这就是我的想法,但它返回一个 Iterable 而不是 Option。
    • 嗯,这很奇怪。他们为什么要那样做?改用 s.flatmap(x=>x)。
    • 也可以写成s flatMap identity
    • 总结以上内容:List(Some(Some("foo")), Some(None), None) map { _ flatMap identity } 产生List[Option[java.lang.String]] = List(Some(foo), None, None),我认为这是 Knut(我听说过的 OP 和第一个名为“Knut”的非北极熊幼崽)想要的.
    【解决方案2】:

    您可以使用 scalaz join 来执行此操作,因为这是 monadic 操作之一:

    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]]
    【解决方案3】:

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

    扁平化现在确实存在。

    和以前一样,

    s getOrElse None
    

    (除了其他答案)也会做同样的事情。

    【讨论】:

    • 现在似乎存在:scala> Some(Some(1)).flatten res10: Option[Int] = Some(1)
    • @Alexy 当我在像Some(Some(Some(1))) 这样的对象上调用flatten 时,我得到Cannot prove that Any <:< Option[B]
    【解决方案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
    • 是的,但这是 Option 中的 Option ... 所以我希望它是 Some(Some("something")) 用于肯定结果和 Some(None) 用于否定结果。那么第三种状态只描述 None 呢?好吧,如果问题出在三态逻辑中,那么它才有意义。
    • 相当于一个future:Some(Some(X))是一个计算出来的值,Some(None)表示future已经结束,没有任何值,None表示future没有返回
    • Option[String] 是否为字符串。让我们把它写成 String + 1,这意味着它可以是任何 String 或其他 1 个东西。那么 Option[Option[String]] 就是 (String + 1) + 1 或 String + 2。也就是说它是一个 String 或者它是其他两件事之一。换句话说,Option[Option[String]] 与 Either[Boolean, String] 同构。我认为后面的结构更清楚地表明,计算要么成功生成字符串,要么可能以两种不同的方式失败。
    • 呵呵,很好的解释——“失败的方法有很多,但成功的方法只有一种。” :-)
    【解决方案5】:

    我认为转换到 Iterable 就好了。使用这些步骤从 Option[Option[String] 转到单个 Option[String]

    s.flatten.headOption 
    

    (返回Option[String]

    【讨论】:

      【解决方案6】:

      你可以像下面这样使用 flatMap:

      val options = List(Some(Some(1)), Some(None), None)
      options map (_ flatMap (a => a))
      

      这会将List[Option[Option[Int]]] 映射到List[Option[Int]]
      如果您只有一个选项,您可以按如下方式使用它:

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

      这会将您的Option[Option[Int]] 扁平化为Option[Int]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-27
        • 2012-01-19
        • 1970-01-01
        • 2018-05-18
        • 2019-04-16
        • 1970-01-01
        • 2020-05-06
        • 2014-04-05
        相关资源
        最近更新 更多