2016-01-13 58 views
0

我有以下的HashMap,其中每個元素都應該映射到堆棧:斯卡拉哈希只有一個所有鍵堆棧

var pos = new HashMap[Int, Stack[Int]] withDefaultValue Stack.empty[Int]   
for(i <- a.length - 1 to 0 by -1) { 
      pos(a(i)).push(i) 
} 

如果a會有元素{4, 6, 6, 4, 6, 6}, 如果我添加上面的代碼之後的下列行:

println("pos(0) is " + pos(0)) 
println("pos(4) is " + pos(4)) 

的輸出將是:

pos(0) is Stack(0, 1, 2, 3, 4, 5) 
pos(4) is Stack(0, 1, 2, 3, 4, 5) 

這是怎麼發生的? 我不想將元素添加到pos(0),但僅限於pos(4)pos(6)a的元素)。

看起來好像只有一個堆棧映射到所有密鑰。我想要每個鍵的堆棧。

回答

2

檢查文檔:

http://www.scala-lang.org/api/current/index.html#scala.collection.mutable.HashMap

方法withDefaultValue藉此值作爲一個普通的參數,它不會被重新計算,因此所有條目共享相同的可變堆棧。

def withDefaultValue(d: B): Map[A, B] 

您應該使用withDefault方法代替。

val pos = new HashMap[Int, Stack[Int]] withDefault (_ => Stack.empty[Int]) 

編輯

上述方案似乎並沒有工作,我得到空棧。與源檢查顯示,默認值是返回,但從未付諸地圖

override def apply(key: A): B = { 
    val result = findEntry(key) 
    if (result eq null) default(key) 
    else result.value 
} 

我想一個解決方案可能是覆蓋applydefault方法添加返回之前映射條目。例如用於default方法:

val pos = new mutable.HashMap[Int, mutable.Stack[Int]]() { 
    override def default(key: Int) = { 
    val newValue = mutable.Stack.empty[Int] 
    this += key -> newValue 
    newValue 
    } 
} 

順便說一句。這是對可變的懲罰,我鼓勵你使用不可變的數據結構。

0

如果你正在尋找沒有這些可變集合一個更地道Scala中,函數式的解決方案,可以這樣考慮:

scala> val a = List(4, 6, 6, 4, 6, 6) 
a: List[Int] = List(4, 6, 6, 4, 6, 6) 

scala> val pos = a.zipWithIndex groupBy {_._1} mapValues { _ map (_._2) } 
pos: scala.collection.immutable.Map[Int,List[Int]] = Map(4 -> List(0, 3), 6 -> List(1, 2, 4, 5)) 

它可以看有些混亂,但如果你打破它,zipWithIndex獲得對的值和它們的位置,groupBy製作從每個值到條目列表的映射,然後使用mapValues將(值,位置)對的列表變成位置列表。

scala> val pairs = a.zipWithIndex 
pairs: List[(Int, Int)] = List((4,0), (6,1), (6,2), (4,3), (6,4), (6,5)) 

scala> val pairsByValue = pairs groupBy (_._1) 
pairsByValue: scala.collection.immutable.Map[Int,List[(Int, Int)]] = Map(4 -> List((4,0), (4,3)), 6 -> List((6,1), (6,2), (6,4), (6,5))) 

scala> val pos = pairsByValue mapValues (_ map (_._2)) 
pos: scala.collection.immutable.Map[Int,List[Int]] = Map(4 -> List(0, 3), 6 -> List(1, 2, 4, 5))