Scalaでimmutable.Mapをmutable.Mapに変換するにはどうすればよいですか?


回答:


126

最もクリーンな方法は、mutable.Mapvarargsファクトリーを使用することです。++アプローチとは異なり、これはCanBuildFromメカニズムを使用するため、ライブラリコードがこれを利用するように記述されている場合、より効率的になる可能性があります。

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

これMapは、ペアを一連のペアとして表示することもできるため機能します。


2
パラメータを渡すときに2行目で使用する構文を説明できますか?コロンは何をしますか?
ハインツィ

7
: _*型の割り当てによく似ており、与えられた式にどの型を割り当てるかをコンパイラに正確に伝えます。ここでそれを「このシーケンスを取り、それをいくつかの可変引数パラメーターとして扱う」と考えることができます。
ケビンライト

16
これが最もクリーンな場合は、コレクションライブラリに問題があります;)
matanster

2
@mattエイリアス化されたインポートを使用すると少し短くなる可能性がありますが、不変性を犠牲にすることはScalaにとって非常に非慣用的であり、私がそれをさらに簡単に見えるようにすることでお勧めしたい種類ではないことを覚えておいてください...好奇心から、コピーを介さない場合、他にどのようにしてよりきれいにそれを行うことを提案できますか?
Kevin Wright

それは私のポイントです、私はできませんが、より良いコレクションライブラリはこれを可能にすることができます、私見。
matanster 2015年

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

1
これの漸近的な時間の複雑さを知っていますか?Clojureは永続的なコレクションを「一時的な」コレクション(つまり、線形型の突然変異関数を持つ可変なコレクション)に変え、O(1)段階的に永続的なコレクションに戻すことができることを知っています。これはのように見えますがO(n)、実装がいかに賢いかに依存します++
イェルクWミッターク

1
@ヨルク-これは間違いないと思いO(n)ます。すべてを変更するときの制限は、でなければなりませんがO(n)、新しいコピーの作成を延期して時間を節約するか、元のマップの代わりに変更セットを読み取ることでアクセス時間を2倍にすることができます。どちらが最もパフォーマンスが良いかは、おそらくユースケースによって異なります。
レックスカー

1
@Rustem-マップは順不同です。それらは、好きな順序で表示されます(ハッシュマップの場合、通常はハッシュキーの順序です)。特に、不変マップには、非常に小さいマップの特別なケースがあり、変更可能マップとは異なります。
レックスカー

@Rustemマップは順序付けされていません。
ダニエルC.ソブラル

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もう少し定型と。
Kevin Wright、

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

Mapimmutableから取得したデフォルト値を持つ空のミュータブルを作成するバリアントがあります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、

右、このソリューションは部分的です。
Alexander Azarov、2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.