¿Cómo puedo convertir immutable.Map
a mutable.Map
en Scala para poder actualizar los valores en Map
?
¿Cómo puedo convertir immutable.Map
a mutable.Map
en Scala para poder actualizar los valores en Map
?
Respuestas:
La forma más limpia sería utilizar la mutable.Map
fábrica de varargs. A diferencia del ++
enfoque, este usa el CanBuildFrom
mecanismo y, por lo tanto, tiene el potencial de ser más eficiente si el código de la biblioteca se escribió para aprovechar esto:
val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*)
Esto funciona porque a Map
también se puede ver como una secuencia de pares.
: _*
es muy parecido a la adscripción de tipos, que le dice al compilador exactamente qué tipo asignar a una expresión dada. Puede pensar en ello aquí como si dijera "toma esta secuencia y trátala como varios parámetros de vararg".
val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap
O(1)
pasos. Esto parece ser O(n)
, aunque eso depende, por supuesto, de cuán inteligente sea la implementación de ++
.
O(n)
. En el límite a medida que cambia todo, debe estarlo O(n)
, aunque podría intentar aplazar la creación de la nueva copia para ahorrar tiempo, o duplicar sus tiempos de acceso leyendo conjuntos de cambios en lugar del mapa original. Cuál funciona mejor probablemente depende de su caso de uso.
¿Qué tal usar 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
con un poco más repetitivo.
Comenzando Scala 2.13
, a través de constructores de fábrica aplicados con .to(factory)
:
Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")
Existe una variante para crear un mutable vacío Map
que tiene valores predeterminados tomados del inmutable Map
. Puede almacenar un valor y anular el predeterminado en cualquier momento:
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
Advertencia (vea el comentario de Rex Kerr): No podrá eliminar los elementos provenientes del mapa inmutable:
scala> mMap.remove(1)
//res5: Option[String] = None
scala> mMap(1)
//res6: String = one