How can I convert immutable.Map
to mutable.Map
in Scala so I can update the values in Map
?
The cleanest way would be to use the mutable.Map
varargs factory. Unlike the ++
approach, this uses the CanBuildFrom
mechanism, and so has the potential to be more efficient if library code was written to take advantage of this:
val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*)
This works because a Map
can also be viewed as a sequence of Pairs.
: _*
is much like type ascription, telling the compiler exactly what type to asign to a given expression. You can think of it here as saying "take this sequence, and treat it as a number of vararg params." –
Kennykeno val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m)
–
Papist val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap
O(1)
steps. This looks to be O(n)
, although that depends of course on how clever the implementation of ++
is. –
Sanctitude O(n)
. In the limit as you change everything, it must be O(n)
, though you could try to defer the creation of the new copy to save time, or you double your access times by reading changesets instead of the original map. Which one performs best probably depends on your use case. –
Zelig Starting Scala 2.13
, via factory builders applied with .to(factory)
:
Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")
How about using collection.breakOut?
import collection.{mutable, immutable, breakOut}
val myImmutableMap = immutable.Map(1->"one",2->"two")
val myMutableMap: mutable.Map[Int, String] = myImmutableMap.map(identity)(breakOut)
mutable.Map#apply
with a bit more boilerplate. –
Kennykeno With scala 2.13, there are two alternatives: the to
method of the source map instance, or the from
method of the destination map's companion object.
scala> import scala.collection.mutable
import scala.collection.mutable
scala> val immutable = Map(1 -> 'a', 2 -> 'b');
val immutable: scala.collection.immutable.Map[Int,Char] = Map(1 -> a, 2 -> b)
scala> val mutableMap1 = mutable.Map.from(immutable)
val mutableMap1: scala.collection.mutable.Map[Int,Char] = HashMap(1 -> a, 2 -> b)
scala> val mutableMap2 = immutable.to(mutable.Map)
val mutableMap2: scala.collection.mutable.Map[Int,Char] = HashMap(1 -> a, 2 -> b)
As you can see, the mutable.Map
implementation was decided by the library.
If you want to choose a particular implementation, for example mutable.HashMap
, replace all occurrences of mutable.Map
with mutable.HashMap
.
There is a variant to create an empty mutable Map
that has default values taken from the immutable Map
. You may store a value and override the default at any time:
scala> import collection.immutable.{Map => IMap}
//import collection.immutable.{Map=>IMap}
scala> import collection.mutable.HashMap
//import collection.mutable.HashMap
scala> val iMap = IMap(1 -> "one", 2 -> "two")
//iMap: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,one), (2,two))
scala> val mMap = new HashMap[Int,String] {
| override def default(key: Int): String = iMap(key)
| }
//mMap: scala.collection.mutable.HashMap[Int,String] = Map()
scala> mMap(1)
//res0: String = one
scala> mMap(2)
//res1: String = two
scala> mMap(3)
//java.util.NoSuchElementException: key not found: 3
// at scala.collection.MapLike$class.default(MapLike.scala:223)
// at scala.collection.immutable.Map$Map2.default(Map.scala:110)
// at scala.collection.MapLike$class.apply(MapLike.scala:134)
// at scala.collection.immutable.Map$Map2.apply(Map.scala:110)
// at $anon$1.default(<console>:9)
// at $anon$1.default(<console>:8)
// at scala.collection.MapLike$class.apply(MapLike.scala:134)....
scala> mMap(2) = "three"
scala> mMap(2)
//res4: String = three
Caveat (see the comment by Rex Kerr): You will not be able to remove the elements coming from the immutable map:
scala> mMap.remove(1)
//res5: Option[String] = None
scala> mMap(1)
//res6: String = one
© 2022 - 2024 — McMap. All rights reserved.