我正在尝试解决Scala中的“简单”练习。我有这个功能:
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)
这是练习的内容:
练习2:实现方差函数(如果均值为m, 方差是math.pow(x - m,2)的平均值,参见定义) of mean和flatMap。
我在想像
这样的东西val xs = List(1.3,2.1,3.2)
val m = mean(xs)
xs flatMap(x=> math.pow(x-m,2)).mean //error!
什么是正确的解决方法?如果可能的话,我也想要一个小的理论解释
答案 0 :(得分:8)
我不会这么简单。
map
上的{p> Option[A]
需要一个函数A => B
并返回Option[B]
,如果原始版本为Some
则返回Some
,并且否则None
。因此Some(2).map(_+2)
给出了Some(4)
,但None[Int].map(_+2)
给出了无。
flatMap
大致相同,但它需要一个函数A => Option[B]
并仍然返回Option[B]
。如果原始文件为None
或给定的函数结果为None
,则结果为None
,否则为Some[B]
。
您不希望flatMap
超过列表,您希望flatMap
选项。我会给你一个提示,它始于:
mean(xs).flatMap(m => ...
在该箭头后,m
为Double
,而不是Option[Double]
。
编辑:
好吧,好吧,既然我们得到了所有的贬低而且没有帮助,这就是完整的答案:
def variance(xs: Seq[Double]): Option[Double] = {
mean(xs).flatMap(m => mean(xs.map(x => Math.pow(x-m, 2))))
}
答案 1 :(得分:1)
Matt Putnam的answer提供了一些很好的指示。通过将其分解成更小的块,我发现更容易理解这个问题。
scala> val xs = List(1.3,2.1,3.2)
xs: List[Double] = List(1.3, 2.1, 3.2)
scala> def mean(xs: Seq[Double]): Option[Double] = {
| if (xs.isEmpty) None
| else Some(xs.sum / xs.length)
| }
mean: (xs: Seq[Double])Option[Double]
计算每个元素与序列平均值的偏差:
scala> mean(xs).map(m => xs.map(x => x-m))
res0: Option[List[Double]] = Some(List(-0.9000000000000001, -0.10000000000000009, 1.0))
map
有效,因为如果mean(xs)
为Some
,则评估x => x-m
。否则它不是,我们得到None
。
现在计算与序列平均值的平方偏差:
scala> mean(xs).map(m => xs.map(x => math.pow(x-m, 2)))
res1: Option[List[Double]] = Some(List(0.8100000000000003, 0.010000000000000018, 1.0))
然后计算其平均值:
scala> mean(xs).map(m => mean(xs.map(x => math.pow(x-m, 2))))
res2: Option[Option[Double]] = Some(Some(0.6066666666666668))
但是,我们的Option
包含Option
,因此我们使用flatMap
来获取第一个Some
的值。因此,具有所需返回类型Option[Double]
的解决方案是:
scala> mean(xs).flatMap(m => mean(xs.map(x => math.pow(x-m, 2))))
res3: Option[Double] = Some(0.6066666666666668)