1

scala でフライバイ シート オブ パンツ スパース ベクトル ライブラリを作成しようとしていますが、長さ 1 のシーケンスに余分な要素を作成または追加しているように見える foldLeft で問題が発生しています。

これが私のスパース加算関数です:

  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 になる値を持つ 2 つのマップを追加すると、問題なく動作します。

scala> Common.addNMaps(Map(1->1), Map(1->1))
res34: scala.collection.immutable.Map[Int,Double] = Map(1 -> 1.0)

しかし、引数が 1 つしかない場合:

scala> Common.addNMaps(Map(1->1))
res33: scala.collection.immutable.Map[Int,Double] = Map(1 -> 2.0)

値の合計が突然 2 になりました。私の推測では、Map(1->1)どうにかシングルが 2 回追加されてfoldLeftいると思いますが、それは推測にすぎません。

私は何を間違っていますか?どうすれCommon.addNMaps(Map(1->1))ば戻ることができMap(1->1.0)ますか?

4

1 に答える 1

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をかける必要があります。m1m2


この場合IntMap、便利なメソッドを持つ を使用できることに注意してください (おそらくHaskell のunionWithに触発されています)。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 MapAPIに含まれていない理由がわかりません。

于 2012-05-17T13:55:22.880 に答える