Scala'da immutable.Map'i mutable.Map'e nasıl dönüştürebilirim?


95

Nasıl dönüştürebilirsiniz immutable.Mapiçin mutable.Mapben değerleri güncelleyebilirsiniz böylece Scala Map?

Yanıtlar:


132

En temiz yol, mutable.Mapvarargs fabrikasını kullanmak olacaktır . ++Yaklaşımdan farklı olarak , bu CanBuildFrommekanizmayı kullanır ve bundan yararlanmak için kütüphane kodu yazıldıysa daha verimli olma potansiyeline sahiptir:

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

Bu işe yarar çünkü a Mapaynı zamanda bir Çift dizisi olarak da görülebilir.


2
Parametreyi geçerken ikinci satırda hangi sözdizimini kullandığınızı açıklayabilir misiniz? Kolon ne yapar?
Heinzi

7
: _*tür tanımına çok benzer, derleyiciye belirli bir ifadeye tam olarak hangi türü atayacağını söyler. Burada "bu diziyi al ve onu bir dizi vararg parametresi olarak ele al" dediğini düşünebilirsiniz.
Kevin Wright

16
Koleksiyon kitaplıklarında bir sorun var, eğer bu en
temizse

2
@matt Aliased import ile biraz daha kısaltılabilir, ancak Scala için değişmezlikten ödün vermenin çok deyimsel olmadığını unutmayın, tam olarak onu daha da kolay hale getirerek canlandıracağım türden bir şey değil ... Merak ediyorum. , kopya yoluyla olmasa bile bunu daha temiz yapmayı başka nasıl önerebilirsin?
Kevin Wright

Demek istediğim bu, yapamam ama daha iyi bir koleksiyon kütüphanesi bunu mümkün kılabilir, IMHO.
matanster

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

1
Bunun asimptotik zaman karmaşıklığının ne olduğunu biliyor musunuz? Clojure'un kalıcı koleksiyonlarından herhangi birini "geçici" bir koleksiyona (yani doğrusal tipte mutasyon işlevlerine sahip değiştirilebilir bir koleksiyona) ve O(1)adım adım kalıcı bir koleksiyona dönüştürebileceğini biliyorum . Bu bakışlar olmaya O(n)Bunun ne kadar zeki uygulanmasına ilişkin elbette bağlı olsa da, ++olduğunu.
Jörg W Mittag

1
@ Jörg - Bunun olduğundan oldukça eminim O(n). Sınırda her şeyi değiştirdiğinizde, O(n)zaman kazanmak için yeni kopyanın oluşturulmasını ertelemeyi deneyebilirsiniz veya orijinal harita yerine değişiklik kümelerini okuyarak erişim sürelerinizi ikiye katlayabilirsiniz. Hangisinin en iyi performansı gösterdiği muhtemelen kullanım durumunuza bağlıdır.
Rex Kerr

1
@Rustem - Haritalar sırasızdır. İstedikleri sırayla görünürler (bir karma haritayla, bu genellikle karma anahtarının sırasıdır). Özellikle, değişmez haritaların, değiştirilebilir haritalardan farklı, gerçekten küçük haritalar için özel durumları vardır.
Rex Kerr

@Rustem Haritalar sipariş edilmemiştir.
Daniel C. Sobral

5

Scala 2.13Aşağıdakilerle uygulanan fabrika üreticileri aracılığıyla başlangıç .to(factory):

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

4

Collection.breakOut kullanmaya ne dersiniz?

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

Bu ise serin, ama temelde aynı şeyi yapar mutable.Map#apply, daha klişe bit ile.
Kevin Wright

2

MapDeğişmezden alınan varsayılan değerlere sahip boş bir değişken oluşturmanın bir varyantı vardır Map. İstediğiniz zaman bir değer saklayabilir ve varsayılanı geçersiz kılabilirsiniz:

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

Uyarı (Rex Kerr'in yorumuna bakın): Değişmez haritadan gelen unsurları kaldıramayacaksınız:

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

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

3
Bu bazı durumlarda kullanışlıdır, ancak yeni haritanızda varsayılan haritanızda bulunan bir öğeyi kaldıramayacağınızı unutmayın; yalnızca varsayılanları kapatabilir ve ortaya çıkarabilirsiniz.
Rex Kerr

Doğru, bu çözüm kısmi.
Alexander Azarov

0

Scala 2.13 ile iki alternatif vardır: tokaynak eşleme örneğinin fromyöntemi veya hedef haritanın yardımcı nesnesinin yöntemi.

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)

Gördüğünüz gibi, mutable.Mapuygulamaya kütüphane tarafından karar verildi. Örneğin mutable.HashMap, belirli bir uygulama seçmek istiyorsanız , tüm oluşumlarını mutable.Mapile değiştirin mutable.HashMap.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.