Perhaps a simple to be answered question, but I did not find a satisfying answer from the API. I am not trying to write nice code, but I am trying to learn more on how certain things work:
I have created an initial HashMap. From an arbitrary list I would like to use map in order to create a list of HashMaps. I add a (key, value) pair to my HashMap within the .map function. Thus, in any successive index from this list the size of the stored HashMap should increase by one (so list(i).size == list(i+1).size - 1 for every i).
But with the following code snipped I get a list of Maps which are all equal (namely the full HashMap). If I print out the growing initial HashMap everything seems right, though.
scala> import scala.collection.mutable.HashMap
val m = new HashMap[Int, Int]
List(1,2,3,4) map {e =>
println(m)
val newM = m += e -> (e+2)
newM
}
Map()
Map(1 -> 3)
Map(1 -> 3, 2 -> 4)
Map(3 -> 5, 1 -> 3, 2 -> 4)
import scala.collection.mutable.HashMap
m: scala.collection.mutable.HashMap[Int,Int] = Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4)
res7: List[scala.collection.mutable.HashMap[Int,Int]] = List(Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4))
What I expected was something like
List(Map(1 -> 2), Map(1 -> 2, 2 -> 4), Map(1 -> 2, 2 -> 4, 3 -> 5), Map(1 -> 2, 2 -> 4, 3 -> 5, 4 -> 6))
The equivalent (I assume it is) version using a generative for loop results in exactly the same result:
scala> for {
i <- 1 to 4
val newM = m += i -> (i+2)
} yield newM
res10: scala.collection.immutable.IndexedSeq[scala.collection.mutable.HashMap[Int,Int]] = Vector(Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4))
scala> for (i <- 1 to 4) yield {
val newM = m += i -> (i+2)
println(m)
newM
}
Map(1 -> 3)
Map(1 -> 3, 2 -> 4)
Map(3 -> 5, 1 -> 3, 2 -> 4)
Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4)
res11: scala.collection.immutable.IndexedSeq[scala.collection.mutable.HashMap[Int,Int]] = Vector(Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4), Map(3 -> 5, 4 -> 6, 1 -> 3, 2 -> 4))
I suppose I am missing a fundamental step, but I just do not see which. I appreciate any further help!
A subsequent question: Obviously the order in which the (key, value) pairs are printed out is always the same (though not in order of how they were elements, but I do not expect this from a Map anyways, this is natural). What happens in the background when the pairs are stored that this always seems to be the case?
m
is a mutable HashMap.
The +=
method adds a new element to that very same map, and returns the map.
You have named the map newM
, but this is a red herring! It's just the very same map m
. So they're all just m
.
If you really want a copy, you can call clone
on m
(e.g. val newM = (m += e -> (e+2)).clone
).
Or, if you want to build up an immutable map as you go, you can use the scan
method:
List(1,2,3,4).scanLeft(collection.immutable.HashMap[Int,Int]()){ (m,e) => m + (e -> (e+2)) }
which takes an item (in this case an empty map) and builds upon it step-by-step, returning the entire history to you when it's done:
res7: List[scala.collection.immutable.HashMap[Int,Int]]
= List(Map(), Map(1 -> 3), Map(1 -> 3, 2 -> 4),
Map(1 -> 3, 2 -> 4, 3 -> 5), Map(1 -> 3, 2 -> 4, 3 -> 5, 4 -> 6))
Better yet, you can
List(1,2,3,4).map(e => e -> (e+2)).toMap
to get your final map without worrying about the building process.