我正在尝试在scala中创建一个按位置的稀疏矢量库,我遇到了foldLeft的一个问题,它似乎是在长度为1的序列上创建或添加一个额外的元素。
这是我的稀疏添加功能:
def addTwoMaps(m1: Map[Int,Double], m2: Map[Int,Double]) =
m1 ++ m2.map{ case (k,v) => k -> (v + m2.getOrElse(k, 0.)) }
这是我的“添加地图序列/稀疏矢量和规范化”功能:
def addNMaps(ms : Map[Int, Double]*) = {
val denom = if (ms.length > 0) ms.length.toDouble else 1
ms.foldLeft(Map.empty[Int, Double])((a,b) => addTwoMaps(a,b)).mapValues(_ / denom)
}
(对于我的特殊情况,每个输入映射的值总和为1,所以我所要做的就是除以参数序列的长度,以确保得到的映射在其值上总和为1)
作为测试用例,如果我添加两个值总和为1的地图,那就可以了:
scala> Common.addNMaps(Map(1->1), Map(1->1))
res34: scala.collection.immutable.Map[Int,Double] = Map(1 -> 1.0)
但如果我只有一个论点:
scala> Common.addNMaps(Map(1->1))
res33: scala.collection.immutable.Map[Int,Double] = Map(1 -> 2.0)
这些值突然变为两个!我的猜测是单Map(1->1)
在foldLeft
中以某种方式被添加两次,但这只是猜测。
我做错了什么?我如何让Common.addNMaps(Map(1->1))
返回Map(1->1.0)
?
答案 0 :(得分:1)
你的addTwoMaps
中有一个拼写错误,应该是:
def addTwoMaps(m1: Map[Int,Double], m2: Map[Int,Double]) =
m1 ++ m2.map{ case (k,v) => k -> (v + m1.getOrElse(k, 0.)) }
您需要在getOrElse
上致电m1
,而不是m2
。
请注意,在这种情况下,您可以使用IntMap
,它有一个方便的unionWith
方法(可能受到Haskell's Data.Map.unionWith
的启发):
import scala.collection.immutable.IntMap
def addNMaps(ms : IntMap[Double]*) = {
val denom = if (ms.length > 0) ms.length else 1
ms.foldLeft(IntMap.empty[Double]) {
(a, b) => a.unionWith(b, (_, x, y) => x + y)
}.mapValues(_ / denom)
}
我不确定为什么unionWith
不属于标准Scala Map
API。