2016-01-13 57 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))