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


Answers:


126

最干净的方法是使用mutable.Mapvarargs工厂。与这种++方法不同,它使用了该CanBuildFrom机制,因此如果编写库代码来利用此机制,则有可能变得更加高效:

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

之所以Map可行,是因为a 也可以视为成对的序列。


2
您能解释一下,传递参数时在第二行中使用什么语法?结肠做什么?
Heinzi 2012年

7
: _*与类型归属非常相似,它告诉编译器将哪种类型分配给给定的表达式。您可以在这里将其视为“采用此序列,并将其视为许多vararg参数”。
凯文·赖特

16
如果这是最干净的,则集合库有问题;)
matanster

2
@matt使用别名导入可以使它更短一些,但是请记住,牺牲不变性对于Scala来说不是惯用的方法,这并不是我想要通过使其看起来更简单来鼓励的事情...出于好奇,如果不通过复制,您还可以提议更整洁地进行此操作吗?
凯文·赖特

这是我的观点,我不能,但是更好的收藏库可以实现这一点,恕我直言。
matanster

41
val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap

1
您知道这是渐近时间复杂度吗?我知道Clojure可以将其任何持久性集合转换为“瞬态”集合(即具有线性类型的突变函数的可变集合),并O(1)逐步转换为持久性集合。这看起来O(n),尽管在如何巧妙的实现,当然取决于++IS。
约尔格W¯¯米塔格

1
@Jörg-我很确定这是O(n)。在更改所有内容的限制中,它必须为O(n),尽管您可以尝试推迟创建新副本以节省时间,或者通过读取更改集而不是原始映射来使访问时间加倍。哪一个性能最好取决于您的用例。
Rex Kerr

1
@Rustem-地图无序。它们将按照其感觉的顺序显示(使用哈希映射,通常是哈希键的顺序)。特别是,不可变映射对于与可变映射不同的非常小的映射具有特殊情况。
Rex Kerr

@Rustem地图未排序。
Daniel C. Sobral

4

如何使用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有一点更多的样板。
凯文·赖特

2

Scala 2.13通过应用.to(factory)以下内容的工厂建造者开始:

Map(1 -> "a", 2 -> "b").to(collection.mutable.Map)
// collection.mutable.Map[Int,String] = HashMap(1 -> "a", 2 -> "b")

1

有一种创建空的可变变量的变体,该可变变量的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

警告(请参阅Rex Kerr的评论):您将无法删除来自不变地图的元素:

scala> mMap.remove(1)
//res5: Option[String] = None

scala> mMap(1)
//res6: String = one

3
在某些情况下这很有用,但是请注意,您无法删除默认地图中存在的新地图中的元素;您只能覆盖和发现默认值。
Rex Kerr

是的,此解决方案是局部的。
亚历山大·阿扎罗夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.