Inside a function of mine I construct a result set by filling a new mutable HashMap with data (if there is a better way - I'd appreciate comments). Then I'd like to return the result set as an immutable HashMap. How to derive an immutable from a mutable?
Asked
Active
Viewed 1.5k times
3 Answers
13
Discussion about returning immutable.Map
vs. immutable.HashMap
notwithstanding, what about simply using the toMap
method:
scala> val m = collection.mutable.HashMap(1 -> 2, 3 -> 4)
m: scala.collection.mutable.HashMap[Int,Int] = Map(3 -> 4, 1 -> 2)
scala> m.toMap
res22: scala.collection.immutable.Map[Int,Int] = Map(3 -> 4, 1 -> 2)
As of 2.9, this uses the method toMap
in TraversableOnce
, which is implemented as follows:
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = {
val b = immutable.Map.newBuilder[T, U]
for (x <- self)
b += x
b.result
}

ebruchez
- 7,760
- 6
- 29
- 41
-
Thanks for introducing 'Map.newBuilder'. I've normally used mutable maps just for the construction of immutable ones. – akauppi Sep 18 '14 at 07:03
-
Is there any tangible difference? I always wondered whether `newBuilder` keeps only one copy of the data in memory or does it perform a full copy of rhe data on `.result`, thus requiring double the memory amount? – matanster Sep 23 '15 at 14:47
-
1You can check the [source](https://github.com/scala/scala/blob/v2.11.7/src/library/scala/collection/mutable/MapBuilder.scala): `MapBuilder.result` just returns `elems`, so it doesn't create a new copy. From this my understanding is that this is exactly the same as doing a `+` operation on the *immutable* collection, and no *mutable* collection is involved. – ebruchez Sep 23 '15 at 16:06
8
scala> val m = collection.mutable.HashMap(1->2,3->4)
m: scala.collection.mutable.HashMap[Int,Int] = Map(3 -> 4, 1 -> 2)
scala> collection.immutable.HashMap() ++ m
res1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
or
scala> collection.immutable.HashMap(m.toSeq:_*)
res2: scala.collection.immutable.HashMap[Int,Int] = Map(1 -> 2, 3 -> 4)

dhg
- 52,383
- 8
- 123
- 144
-
But the result is an `immutable.Map`, not an `immutable.HashMap` then! The function is meant to return `immutable.HashMap`. – Ivan Jan 30 '12 at 00:25
-
You can specify whatever type you want. If you want the type to be `Map`, do `Map() ++ m` – dhg Jan 30 '12 at 00:26
-
I want `immutable.HashMap`, but `immutable.HashMap ++ m` (where `m` is a `mutable.HashMap`) returns `immutable.Map`. – Ivan Jan 30 '12 at 00:28
-
The result is `immutable.HashMap` if you say `immutable.HashMap(m.toSeq:_*)`, as shown in the answer. – dhg Jan 30 '12 at 00:29
-
By the way, what's your reason for needing the type to be `HashMap`? It's generally best to only assume the "interface" type, like `Map` to allow your program to be flexible for different `Map` implementations. – dhg Jan 30 '12 at 00:37
-
3Yes, it's better to consume as generic types as possible, but to provide as specific types as possible, isn't it? – Ivan Jan 30 '12 at 00:40
-
1@Ivan Not really. If you provide a `HashMap`, then you'll never be able to change into something else. Say, for example, you later need a `LinkedHashMap`, but someone is already depending on you returning a `HashMap`. Inside a module, that's ok. On anything public, keep to interfaces. – Daniel C. Sobral Jan 30 '12 at 02:30
-
@daniel-c-sobral, but aren't there any side effects of turning a `HashMap` into a `Map`? Doesn't `HashMap` provide any functionality a bare `Map` doesn't? It is still not clear for me whether or not I have reasons to return a `HashMap`, I am afraid a reason can actually exists so I can regret switching to a `Map` in future. – Ivan Feb 17 '12 at 01:26
2
If you have a map : logMap: Map[String, String]
just need to do : logMap.toMap()

Sandeep Das
- 1,010
- 9
- 22