scala(scanLeft) - 如何(在功能上)获取具有累积值/频率的Map

时间:2018-02-28 12:13:18

标签: scala fold

我是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 吗?请帮忙

3 个答案:

答案 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))

(使用简要说明)。