Каким образом можно преобразовать immutable.Map
в mutable.Map
в Scala , так что я могу обновить значения в Map
?
Ответы:
Самый чистый способ - использовать mutable.Map
фабрику varargs. В отличие от ++
подхода, здесь используется CanBuildFrom
механизм, и поэтому он может быть более эффективным, если библиотечный код был написан с учетом этого:
val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*)
Это работает, потому что a Map
также можно рассматривать как последовательность пар.
: _*
очень похоже на присвоение типа, сообщая компилятору, какой именно тип присвоить данному выражению. Вы можете думать об этом здесь как о том, чтобы «взять эту последовательность и рассматривать ее как несколько параметров vararg».
val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap
O(1)
. Это выглядит быть O(n)
, хотя это зависит, конечно , от того, насколько умный реализации ++
ИС.
O(n)
. В пределе, когда вы меняете все, это должно быть O(n)
, хотя вы можете попытаться отложить создание новой копии, чтобы сэкономить время, или вы удвоите время доступа, читая наборы изменений вместо исходной карты. Какой из них работает лучше всего, вероятно, зависит от вашего варианта использования.
Запускается Scala 2.13
заводскими сборщиками с применением .to(factory)
:
Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")
Как насчет использования 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
с немного больше шаблоннога.
Существует вариант создания пустого изменяемого объекта Map
со значениями по умолчанию, взятыми из неизменяемого Map
. Вы можете сохранить значение и изменить значение по умолчанию в любое время:
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
Предостережение (см. Комментарий Рекса Керра): вы не сможете удалить элементы, поступающие с неизменяемой карты:
scala> mMap.remove(1)
//res5: Option[String] = None
scala> mMap(1)
//res6: String = one
В scala 2.13 есть две альтернативы: to
метод экземпляра исходной карты или from
метод сопутствующего объекта целевой карты.
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)
Как видите, mutable.Map
реализация решила библиотека. Если вы хотите выбрать конкретную реализацию, например mutable.HashMap
, заменить все вхождения mutable.Map
с mutable.HashMap
.