Wie kann ich unveränderliche.Map in veränderbare.Map in Scala konvertieren?

93

Wie kann ich in Scala konvertieren immutable.Map, mutable.Mapum die Werte in zu aktualisieren Map?

Łukasz Lew
quelle

Antworten:

126

Am saubersten wäre es, die mutable.MapVarargs-Fabrik zu benutzen . Im Gegensatz zum ++Ansatz verwendet dies den CanBuildFromMechanismus und kann daher effizienter sein, wenn Bibliothekscode geschrieben wurde, um dies auszunutzen:

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

Dies funktioniert, weil a Mapauch als Folge von Paaren angesehen werden kann.

Kevin Wright
quelle
2
Können Sie erklären, welche Syntax Sie in der zweiten Zeile verwenden, wenn Sie den Parameter übergeben? Was macht der Doppelpunkt?
Heinzi
7
: _*ähnelt der Typzuweisung und teilt dem Compiler genau mit, welcher Typ einem bestimmten Ausdruck zugewiesen werden soll. Sie können sich das hier so vorstellen, dass Sie sagen: "Nehmen Sie diese Sequenz und behandeln Sie sie als eine Reihe von vararg-Parametern."
Kevin Wright
16
Es stimmt etwas nicht mit den Sammlungsbibliotheken, wenn dies die sauberste ist;)
Matanster
2
@ Matt Es könnte etwas kürzer mit aliased Importen gemacht werden, aber bedenken Sie, dass Unveränderlichkeit zu opfern ist sehr nicht-idiomatische für Scala, nicht genau das , was ich es , indem sie enourage würde aussehen noch einfacher ... Aus Neugier , wie sonst könnten Sie vorschlagen, es sauberer zu machen, wenn nicht über eine Kopie?
Kevin Wright
Das ist mein Punkt, ich kann nicht, aber eine bessere Sammlungsbibliothek könnte dies ermöglichen, IMHO.
Matanster
41
val myImmutableMap = collection.immutable.Map(1->"one",2->"two")
val myMutableMap = collection.mutable.Map() ++ myImmutableMap
Rex Kerr
quelle
1
Wissen Sie, wie asymptotisch die zeitliche Komplexität ist? Ich weiß, dass Clojure jede seiner persistenten Sammlungen in eine "vorübergehende" (dh eine veränderbare mit linear typisierten Mutationsfunktionen) und schrittweise in eine persistente Sammlung umwandeln kann O(1). Dies scheint zu sein O(n), obwohl dies natürlich davon abhängt, wie clever die Implementierung ++ist.
Jörg W Mittag
1
@ Jörg - da bin ich mir ziemlich sicher O(n). Wenn Sie alles ändern, muss dies der Fall sein O(n). Sie können jedoch versuchen, die Erstellung der neuen Kopie zu verschieben, um Zeit zu sparen, oder Sie verdoppeln Ihre Zugriffszeiten, indem Sie Änderungssätze anstelle der ursprünglichen Karte lesen. Welche Leistung am besten erbracht wird, hängt wahrscheinlich von Ihrem Anwendungsfall ab.
Rex Kerr
1
@Rustem - Karten sind ungeordnet. Sie werden in der Reihenfolge angezeigt, in der sie sich fühlen (bei einer Hash-Map ist dies normalerweise die Reihenfolge des Hash-Schlüssels). Insbesondere unveränderliche Karten haben Sonderfälle für wirklich winzige Karten, die sich von veränderlichen Karten unterscheiden.
Rex Kerr
@Rustem Maps werden nicht bestellt.
Daniel C. Sobral
4

Wie wäre es mit 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)
ymnk
quelle
Es ist cool, macht aber im Grunde das Gleiche wie mutable.Map#applymit etwas mehr Boilerplate.
Kevin Wright
2

Starten Scala 2.13über Fabrikbauer angewendet mit .to(factory):

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

Es gibt eine Variante, um eine leere veränderbare Variable zu erstellen Map, deren Standardwerte von der unveränderlichen übernommen wurden Map. Sie können jederzeit einen Wert speichern und den Standardwert überschreiben:

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

Vorsichtsmaßnahme (siehe Kommentar von Rex Kerr): Sie können die Elemente aus der unveränderlichen Karte nicht entfernen:

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

scala> mMap(1)
//res6: String = one
Alexander Azarov
quelle
3
Dies ist in einigen Fällen nützlich. Beachten Sie jedoch, dass Sie kein Element in Ihrer neuen Karte entfernen können, das in Ihrer Standardkarte vorhanden war. Sie können nur die Standardeinstellungen abdecken und aufdecken.
Rex Kerr
Richtig, diese Lösung ist teilweise.
Alexander Azarov