13

基本上,我正在寻找最类似于 scala 的方式来执行以下操作:

def sum(value1: Option[Int], value2: Option[Int]): Option[Int] = 
  if(value1.isDefined && value2.isDefined) Some(value1.get + value2.get)
  else if(value1.isDefined && value2.isEmpty) value1
  else if(value1.isEmpty && value2.isDefined) value2
  else None

这给出了正确的输出:

sum(Some(5), Some(3))  // result = Some(8)
sum(Some(5), None)     // result = Some(5)
sum(None, Some(3))     // result = Some(3)
sum(None, None)        // result = None

然而,要总结两个以上的选项,我必须使用太多if的 s 或使用某种循环。

编辑-1:

在写这个问题时,我想出了一个答案:

def sum2(value1: Option[Int], value2: Option[Int]): Option[Int] = 
  value1.toList ::: value2.toList reduceLeftOption { _ + _ }

对于我没有经验的人来说,这看起来非常地道。这甚至可以使用两个以上的值。然而,是否可以在不转换为列表的情况下做同样的事情?

编辑-2:

我最终得到了这个解决方案(感谢ziggystar):

def sum(values: Option[Int]*): Option[Int] = 
  values.flatten reduceLeftOption { _ + _ }

编辑-3:

感谢Landei的另一种选择:

def sum(values: Option[Int]*): Option[Int] = 
  values collect { case Some(n) => n } reduceLeftOption { _ + _ }
4

5 回答 5

10

怎么样:

scala> def sum(values: Option[Int]*): Option[Int] = values.flatten match {
     | case Nil => None                                                   
     | case l => Some(l.sum)                                              
     | }
sum: (values: Option[Int]*)Option[Int]

scala> sum(Some(1), None)
res0: Option[Int] = Some(1)

scala> sum(Some(1), Some(4))
res1: Option[Int] = Some(5)

scala> sum(Some(1), Some(4), Some(-5))
res3: Option[Int] = Some(0)

scala> sum(None, None)                
res4: Option[Int] = None

编辑

如果所有参数都为无,那么返回 0 可能是明智的。在这种情况下,函数将减少到values.flatten.sum

于 2011-04-29T13:46:33.743 回答
7
scala> def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
     |   case (Some(x), Some(y)) => Some(x + y)
     |   case (Some(x), None) => Some(x)
     |   case (None, Some(y)) => Some(y)
     |   case _ => None
     | }
sum: (a: Option[Int],b: Option[Int])Option[Int]

scala> sum(Some(5), Some(3))
res0: Option[Int] = Some(8)

scala> sum(Some(5), None)
res1: Option[Int] = Some(5)

scala> sum(None, Some(3))
res2: Option[Int] = Some(3)

scala> sum(None, None)
res3: Option[Int] = None
于 2011-04-29T14:03:23.773 回答
5

另一种解决方案是:

def sum(values: Option[Int]*): Int = values.collect{case Some(n) => n}.sum

虽然在当前情况下flatten显然更方便,但该collect版本更灵活,因为它允许执行映射并具有额外的过滤条件或复杂模式。例如,假设您希望得到所有偶数平方和的值:

values.collect{case Some(n) if n mod 2 == 0 => n*n}.sum
于 2011-04-29T21:12:33.350 回答
5

您可以使用以下事实使其非常简洁,即有一个Semigroup实例Option完全符合您的要求。您可以使用scalazcats。这是一个使用示例cats

import cats.std.option._
import cats.syntax.semigroup._
import cats.std.int._

Option(1) |+| Option(2) // Some(3)
Option(1) |+| None      // Some(1)
None      |+| Option(2) // Some(2)

所以你的sum变成:

def sum(v1: Option[Int], v2: Option[Int]): Option[Int] = v1 |+| v2
于 2016-04-17T18:25:32.013 回答
4

michael.kebe 的简化解,稍微看一些基本的数学规则:

def sum(a: Option[Int], b: Option[Int]) = (a,b) match {
  case (None,None) => None
  case _ => Some(a.getOrElse(0)+b.getOrElse(0))
}

scala> sum(Some(5), Some(3))  // result = Some(8)
res6: Option[Int] = Some(8)

scala> sum(Some(5), None)     // result = Some(5)
res7: Option[Int] = Some(5)

scala> sum(None, Some(3))     // result = Some(3)
res8: Option[Int] = Some(3)

scala> sum(None, None)        // result = None
res9: Option[Int] = None
于 2011-04-30T10:20:09.360 回答