我是Scala的新手,并尝试将具有累积频率的地图作为地图中的值与各个地图一起使用。因此(对于持久化ListMap等顺序的不可变Map)value(i)是原始Map中所有值的总和,包括i:
val map = ListMap(0.0 -> 0.1, 0.01 -> 0.2, 0.05 -> 0.3, 0.1 -> 0.4)
val resultMap = ListMap(0.0 -> 0.1, 0.01 -> 0.3, 0.05 -> 0.6, 0.1 -> 1.0)
由于我需要访问以前的键值对,我想出了一个迭代实现,它使用了mutable.LinkedHashMap和一个运行总计,但我发现它很乱,仍在寻找一种方法来获得一个来自不可变的的可变映射(如下面第3行所示):
var cummulativeMap0 = mutable.LinkedHashMap.empty[Double, Double]
var total = 0.0
//line3:
val copyMap = mutable.LinkedHashMap(0.0->0.1, 0.01->0.2, 0.05->0.3, 0.1->0.4)
map.foreach {
(kv) => {
total = total + copyMap.remove(kv._1).get
cummulativeMap0.put(kv._1 , total)
}
}
cummulativeMap0
或者我可以使用scanLeft,但只需要分割2个列表中的键和值的成本,以便稍后压缩:
val cummValues = map.values.scanLeft(0.0){ (a, b)=>a+b }.tail
val cummmulativeMap2 = (map.keys zip cummValues).toMap
实现这一目标的最惯用/最实用的方法是什么,它可以直接在地图上使用 scanLeft 吗?请帮忙
答案 0 :(得分:4)
我相信你可以使用初始值中的虚拟键扫描地图上的元素:
val result = map.scanLeft((0.0, 0.0)){case ((_, av),(bk,bv)) => (bk, av + bv)}.tail
答案 1 :(得分:3)
如果您不想拉链解压缩,请忽略每个步骤中的上一个键:
import scala.collection.immutable._
val map = ListMap(0.0 -> 0.1, 0.01 -> 0.2, 0.05 -> 0.3, 0.1 -> 0.4)
val res = map.scanLeft((0.0, 0.0)){
case ((_, acc), (x, y)) => (x, acc + y)
}
println(res)
给你:
ListMap(0.0 -> 0.1, 0.01 -> 0.3, 0.05 -> 0.6, 0.1 -> 1.0)
(达到机器精度,从输出中截断一些零)
答案 2 :(得分:0)
我想出了zip + map,主要是因为我不知道scanLeft。 :)
scala> val imap = List(0 -> 1, 1 -> 2, 5 -> 3, 1 -> 4)
map: List[(Int, Int)] = List((0,1), (1,2), (5,3), (1,4))
// add neutral element to start with for first element
scala> val m = imap.zip ((0,0) :: imap)
m: List[((Int, Int), (Int, Int))] = List(((0,1),(0,0)), ((1,2),(0,1)), ((5,3),(1,2)), ((1,4),(5,3)))
// same as in scanLeft:
scala> m.map {case ((a, b), (c, d)) => (a, b + d)}
res153: List[(Int, Int)] = List((0,1), (1,3), (5,5), (1,7))
(使用简要说明)。