Scala:如何使用flatMap和Options计算Seq [Double]的方差?

时间:2015-02-27 19:26:20

标签: scala

我正在尝试解决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!

什么是正确的解决方法?如果可能的话,我也想要一个小的理论解释

2 个答案:

答案 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 => ...

在该箭头后,mDouble,而不是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)