Scala MapReduce过滤器

时间:2018-03-08 21:19:45

标签: scala functional-programming mapreduce

有没有办法在Scala中执行以下操作?

假设我有一个大小为15的Double数组:

[10,20,30,40,50,60,70,80,Double.NaN,Double.NaN,110,120,130,140,150]

我想使用map reduce将所有Double.NaN(从左到右)替换为数组中最后四个值的平均值。因此,第一个Double.NaN被替换为60,下一个Double.NaN被替换为64(即,此计算中使用先前在索引8处计算的60)。

到目前为止,我已使用函数类型参数来获取Double.NaN的位置。

2 个答案:

答案 0 :(得分:1)

我不确定你到底是什么意思" map-reduce"在这种情况下。它看起来更像是scanLeft的用例:

import scala.collection.immutable.Queue
val input = List[Double](
  10,20,30,40,50,60,70,80,Double.NaN,
  Double.NaN,110,120,130,140,150
)
val patched = input.
  scanLeft((Queue.fill(5)(0d), 0d)){ 
    case ((q, _), x) => { 
      val y = if (x.isNaN) q.sum / 5 else x; 
      (q.dequeue._2.enqueue(y), y)
    }
  }.unzip._2.tail

创建结果:

List(10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 60.0, 64.0, 110.0, 120.0, 130.0, 140.0, 150.0)

一般情况下,除非差距很小,否则这对于典型的map-reduce工作流程无效,因为

  • 结果列表中的每个值都可以依赖于左侧的任意多个值,因此您无法在独立块中单独剪切数据集,也可以独立地map剪切数据集。
  • 你没有减少任何东西,你想要一个补丁列表

如果你没有映射而不是缩小,我就不会把它称为" map-reduce"。

顺便说一下:上面的代码适用于" 5"的任何(正整数)值。

答案 1 :(得分:0)

请注意,对给定示例(50,60,70,80)中第一个NaN的最后四个值求平均得到65,而不是60.最后五个将给出60.

它必须是map-reduce吗?折叠怎么样?

(List[Double]() /: listOfDoubles)((acc: List[Double], double: Double) => {(if (double.isNaN)
  acc match {
    case Nil => 0.0 // first double in the list
    case _ => {
      val last5 = acc.take(5)
      (0.0 /: last5)(_ + _) / last5.size // in case there's only a last 1, 2, 3, or 4 instead of 5
      }
    }
else double) :: acc}).reverse