如何将此foldLeft:Double表达式转换为使用Option [Double]?

Lun*_*ore 9 functional-programming scala

任何人都可以帮助这个Scala新手吗?以前,我们在具有以下数量的实体列表中汇总了一些数量:

sum = entities.foldLeft(0.0)(_ + _.quantity)
Run Code Online (Sandbox Code Playgroud)

现在数量是一个Option[Double],总和也是.如何使用惯用的Scala转换它?

如果任何实体的数量是None那么总和也应该是None.否则总和应该是Some(total).

编辑:将此内容放入单元测试中,以便我可以尝试所有答案.请注意,如果任何数量为无,我确实需要结果为无,因为缺少数量意味着我们还没有完成,所以总数应该反映这一点.即使你没有得到正确的答案,如果你帮助引导我或其他人,或者帮助我学习新的东西,我会赞成.

编辑:@ sepp2k赢得了工作解决方案和解释.感谢大家的学习!

sep*_*p2k 9

您可以使用Option's flatMapmap方法组合两个Options,以便结果将是Some(f(x,y))两个Options Some(x)和/ Some(y)None其他.

entities.foldLeft(Some(0.0):Option[Double]) {
    (acco, x) => acco.flatMap(acc => x.quantity.map(_ + acc))
}
Run Code Online (Sandbox Code Playgroud)

编辑以回应您的评论:

这是一个示例用法:

scala> case class Foo(quantity:Option[Double]) {}
defined class Foo
scala> val entities: List[Foo] = List(Foo(Some(2.0)), Foo(Some(1.0)), Foo(None))
scala> entities.foldLeft(Some(0.0):Option[Double]) {
    (acco, x) => acco.flatMap(acc => x.quantity.map(_ + acc))
}
res0: Option[Double] = None

scala> val entities: List[Foo] = List(Foo(Some(2.0)), Foo(Some(1.0)))                                  
scala> entities.foldLeft(Some(0.0):Option[Double]) {
    (acco, x) => acco.flatMap(acc => x.quantity.map(_ + acc))
}
res1: Option[Double] = Some(3.0)
Run Code Online (Sandbox Code Playgroud)

所以,是的,None如果有任何实体,它将返回None.

关于mapflatMap:

map采用f类型的函数A => B并返回Some(f(x))for Some(x)Nonefor None.

xo.flatMap(f)其中f是类型的函数A => Option[B]xoOption[A],返回Some(y)IFF xoSome(x)f(x)Some(y).在其他情况下(即,如果xoNone或者f(x)None)返回None.

所以表达式acco.flatMap(acc => x.quantity.map(_ + acc))返回y + acciff x.quantityis Some(y)accois Some(acc).如果一个或两个的x.quantityacco都是None,结果将是无法比拟的.因为这是在折叠内,这意味着对于下一次迭代,值acco也将是None,因此最终结果将是None.