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


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.


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

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)

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")

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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.