如何在Scala中将immutable.Map转换为mutable.Map?

如何在Scala中将immutable.Map转换为mutable.Map?,scala,dictionary,scala-2.8,Scala,Dictionary,Scala 2.8,如何在Scala中将immutable.Map转换为mutable.Map,以便更新Map中的值?如何使用collection.breakOut val myImmutableMap = collection.immutable.Map(1->"one",2->"two") val myMutableMap = collection.mutable.Map() ++ myImmutableMap import collection.{mutable, immutable, brea

如何在Scala中将
immutable.Map
转换为
mutable.Map
,以便更新
Map
中的值?

如何使用collection.breakOut

val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap
import collection.{mutable, immutable, breakOut}
val myImmutableMap = immutable.Map(1->"one",2->"two")
val myMutableMap: mutable.Map[Int, String] = myImmutableMap.map(identity)(breakOut)

有一个变量可以创建一个空的可变
映射
,它的默认值取自不可变
映射
。您可以随时存储一个值并覆盖默认值:

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

最干净的方法是使用
mutable.Map
varargs工厂。与
++
方法不同,它使用了
CanBuildFrom
机制,因此,如果编写库代码以利用这一点,则有可能提高效率:

val m = collection.immutable.Map(1->"one",2->"Two")
val n = collection.mutable.Map(m.toSeq: _*) 

这是因为
Map
也可以被视为成对的序列。

通过工厂构建器启动
Scala 2.13
,应用:


在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

,您知道它的渐近时间复杂度是多少吗?我知道Clojure可以在
O(1)
步骤中将其任何持久性集合转换为“瞬时”集合(即具有线性类型变异函数的可变集合),然后再转换为持久性集合。这看起来是
O(n)
,当然这取决于
++
的实现有多聪明。@Jörg-我很确定这是
O(n)
。在更改所有内容的限制中,它必须是
O(n)
,但您可以尝试推迟创建新副本以节省时间,或者通过读取更改集而不是原始地图来加倍访问时间。哪一个性能最好可能取决于您的用例。@Rustem-map是无序的。它们将以自己喜欢的顺序出现(对于哈希映射,通常是哈希键的顺序)。特别是,不可变映射对于与可变映射不同的非常小的映射有特殊情况。@Rustem映射没有顺序。这在某些情况下很有用,但请注意,您无法删除默认映射中存在的新映射中的元素;您只能覆盖和揭示默认值。对,这个解决方案是局部的。它很酷,但基本上与
mutable.Map#apply
做了相同的事情,并提供了更多的样板文件。您能解释一下,在传递参数时第二行使用了什么语法吗?冒号的作用是什么?
:*
非常类似于类型归属,它确切地告诉编译器将什么类型分配给给定的表达式。在这里,您可以将其视为“接受此序列,并将其视为多个vararg参数。”如果这是最干净的,则集合库有问题;)@matt使用别名导入可以将其缩短一点,但请记住,牺牲不变性对于Scala来说是非常不习惯的,而不是我希望通过使其看起来更简单来实现的那种事情。。。出于好奇,如果不是通过拷贝,你还能提出更干净的方法吗?这是我的观点,我不能,但一个更好的藏书库可以让这成为可能,伊姆霍。
Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")
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)