【问题标题】:Do something when exactly one option is non-empty当只有一个选项不为空时做某事
【发布时间】:2017-04-08 20:12:05
【问题描述】:

如果两个选项中的一个不为空,我想计算一些东西。显然这可以通过模式匹配来完成,但有更好的方法吗?

(o1, o2) match {
  case (Some(o), None) => Some(compute(o))
  case (None, Some(o)) => Some(compute(o))
  case _ => None
}

【问题讨论】:

    标签: scala collections


    【解决方案1】:

    你可以这样做:

    if (o1.isEmpty ^ o2.isEmpty)
      List(o1,o2).flatMap(_.map(x=>Some(compute(x)))).head
    else
      None
    

    但是模式匹配可能是更好的方法。

    【讨论】:

    • 第二行能否简化为List(o1,o2).map(_.map(compute)).headList(o1,o2).flatten.map(compute).headOption
    • 或者更彻底,致:if (o1.isEmpty ^ o2.isEmpty) (o1 orElse o2).map(compute) else None?
    • 是的,我喜欢“激进”的。
    【解决方案2】:

    感谢@Suma 提供的帮助,我想出了除当前解决方案之外的其他解决方案:

    由于输入始终采用Option(x) 的形式:

    Iterator(Seq(o1,o2).filter(_!=None))
      .takeWhile(_.length==1)
      .map( x => compute(x.head.get))
      .toSeq.headOption
    

    使用迭代器还允许将一系列值传递给输入。当且仅当定义了序列中的一个值时,才会完成最终映射。

    【讨论】:

    • filter(a => Option(a).isDefined 的用途是什么 - Option(a) 总是被定义,除非 anull。当您已经知道temp 仅具有一个元素时,reduceOption 的目的是什么?这不是和headOption一样吗?我也没有看到代码中的任何地方使用了compute
    • 好多了。恐怕你不能做compute(temp.headOption.flatten),它必须是temp.head.map(compute)
    • @Suma:编译器并没有在我的 IDE 中报错。我这样做是因为对于某些条目,我得到了 Some(Some(4))。我试图不对compute 的工作原理做出任何假设。我想用什么实现compute 我的代码中断。
    • 您的代码无法使用 compute(x: Int): Int 编译给我 - compute 需要 Option 的内容作为参数,而不是 Option 本身。
    • 您绝对应该在模式匹配中避免使用asInstanceOf - 它几乎永远不会完成,而是使用提取器 - 如果不确定如何,请查看一些示例。至于“如果输入总是采用 Some(x) 的形式”——是的,o1 和 o2 总是Option(有时是Some,有时是None)。
    【解决方案3】:

    pedrofurla 的已删除答案的启发,该答案试图使用o1 orElse o2 map { compute },一种可能性是定义xorElse,其余的很容易:

    implicit class XorElse[T](o1: Option[T]) {
      def xorElse[A >: T](o2: Option[A]): Option[A] = {
        if (o1.isDefined != o2.isDefined) o1 orElse o2
        else None
      }
    }
    
    (o1 xorElse o2).map(compute)
    

    我发现的另一种可能性是使用模式匹配,但使用Seq 连接,以便使用相同的代码处理两种情况。这种方法的优点是它可以扩展到任意数量的选项,它总是会在只有一个时进行评估:

      o1.toSeq ++ o2 match {
        case Seq(one) => Some(compute(one))
        case _ => None
      }
    

    【讨论】:

    • 如果 o1=None 和 o2=Some(4),顶级解决方案无法编译。为了让它工作,似乎 o1 永远不应该是 None。
    • @jrook 您通常不使用None 类型的变量,而是使用值None 并输入Option。你可以这样测试:o1: Option[Int] = None 或(我更喜欢)o1 = Option.empty[Int]
    【解决方案4】:

    只需初始化一个序列,然后展平

    Seq(o1, o2).flatten match {
      case Seq(o) => Some(compute(o))
      case _ => None
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多