Как преобразовать immutable.Map
в mutable.Map
в Scala, чтобы обновить значения в Map
?
Как преобразовать immutable.Map в mutable.Map в Scala?
Ответы (6)
Самым чистым способом было бы использовать фабрику mutable.Map
varargs. В отличие от подхода ++
здесь используется механизм CanBuildFrom
, и поэтому он может быть более эффективным, если код библиотеки будет написан с учетом этого:
val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*)
Это работает, потому что Map
также можно рассматривать как последовательность пар.
: _*
очень похоже на приписывание типа, сообщая компилятору, какой именно тип следует присвоить данному выражению. Вы можете думать об этом здесь как о том, чтобы взять эту последовательность и рассматривать ее как ряд параметров vararg.
- person Kevin Wright; 06.06.2012
Начиная с 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
, но с немного большим количеством шаблонов.
- person Kevin Wright; 20.02.2011
Существует вариант создания пустого изменяемого 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
.
O(1)
шагов. Это выглядит как O(n)
, хотя это, конечно, зависит от того, насколько умна реализация ++
.
- person Jörg W Mittag; 18.02.2011
O(n)
. В пределе, когда вы меняете все, это должно быть O(n)
, хотя вы можете попробовать отложить создание новой копии, чтобы сэкономить время, или удвоить время доступа, читая наборы изменений вместо исходной карты. Какой из них работает лучше всего, вероятно, зависит от вашего варианта использования.
- person Rex Kerr; 18.02.2011