Каким образом можно преобразовать 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.