有没有办法在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
的位置。
答案 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