ฉันจะแปลงไม่เปลี่ยนรูปได้แผนที่เป็นไม่แน่นอนแผนที่ใน Scala ได้อย่างไร


คำตอบ:


132

วิธีที่สะอาดที่สุดคือใช้mutable.Mapโรงงาน varargs ซึ่งแตกต่างจาก++วิธีการนี้ใช้CanBuildFromกลไกและมีศักยภาพที่จะมีประสิทธิภาพมากขึ้นหากมีการเขียนโค้ดไลบรารีเพื่อใช้ประโยชน์จากสิ่งนี้:

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

ใช้งานได้เนื่องจากMapสามารถดูเป็นลำดับของคู่ได้


2
คุณอธิบายได้ไหมว่าคุณใช้ไวยากรณ์อะไรในบรรทัดที่สองเมื่อส่งผ่านพารามิเตอร์ ลำไส้ใหญ่ทำหน้าที่อะไร?
Heinzi

7
: _*เหมือนกับคำอธิบายประเภทโดยบอกคอมไพเลอร์ว่าประเภทใดที่จะเทียบกับนิพจน์ที่กำหนด คุณสามารถคิดได้ที่นี่ว่า "รับลำดับนี้และถือว่ามันเป็นพารามิเตอร์ของวาราร์ก"
Kevin Wright

16
มีบางอย่างผิดปกติกับไลบรารีคอลเลกชันหากนี่เป็นสิ่งที่สะอาดที่สุด;)
matanster

2
@matt อาจทำให้สั้นลงเล็กน้อยด้วยการนำเข้านามแฝง แต่โปรดจำไว้ว่าการเสียสละความไม่เปลี่ยนรูปนั้นไม่ใช่สำนวนสำหรับ Scala ไม่ใช่สิ่งที่ฉันต้องการโดยทำให้มันดูง่ายขึ้น ... คุณจะเสนอให้ทำอย่างสะอาดมากขึ้นได้อย่างไรถ้าไม่ใช่ผ่านสำเนา
Kevin Wright

นั่นคือประเด็นของฉันฉันทำไม่ได้ แต่ไลบรารีคอลเลกชันที่ดีกว่าสามารถทำให้สิ่งนี้เป็นไปได้ IMHO
matanster

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

1
คุณรู้ไหมว่าความซับซ้อนของเวลาที่ไม่แสดงอาการของสิ่งนี้คืออะไร? ฉันรู้ว่า Clojure สามารถเปลี่ยนคอลเลกชันถาวรใด ๆ ของมันให้กลายเป็น "ชั่วคราว" ได้ (นั่นคืออันที่เปลี่ยนแปลงได้โดยมีฟังก์ชันการกลายพันธุ์ที่พิมพ์เป็นเส้นตรง) และกลับไปเป็นคอลเลกชันถาวรในO(1)ขั้นตอนต่างๆ นี้มีลักษณะที่จะO(n)ถึงแม้ว่ามันจะขึ้นอยู่กับการเรียนการสอนเกี่ยวกับวิธีการที่ชาญฉลาดการดำเนินการ++คือ
Jörg W Mittag

1
@ Jörg - O(n)ผมค่อนข้างมั่นใจว่าคนนี้เป็น ในขีด จำกัด เมื่อคุณเปลี่ยนแปลงทุกอย่างก็ต้องเป็นO(n)เช่นนั้นแม้ว่าคุณจะพยายามเลื่อนการสร้างสำเนาใหม่เพื่อประหยัดเวลาหรือคุณเพิ่มเวลาในการเข้าถึงเป็นสองเท่าโดยการอ่านชุดการเปลี่ยนแปลงแทนแผนที่เดิม ข้อใดมีประสิทธิภาพสูงสุดอาจขึ้นอยู่กับกรณีการใช้งานของคุณ
Rex Kerr

1
@Rustem - แผนที่ไม่เรียงลำดับ โดยจะปรากฏในลำดับใดก็ตามที่พวกเขาต้องการ (หากมีแผนที่แฮชโดยทั่วไปจะเป็นลำดับของคีย์แฮช) โดยเฉพาะอย่างยิ่งแผนที่ที่ไม่เปลี่ยนรูปจะมีกรณีพิเศษสำหรับแผนที่ขนาดเล็กจริงๆซึ่งแตกต่างจากแผนที่ที่เปลี่ยนแปลงไม่ได้
Rex Kerr

@Rustem Maps ไม่ได้รับคำสั่ง
Daniel C. Sobral

5

เริ่มScala 2.13จากผู้สร้างโรงงานที่ใช้กับ.to(factory):

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

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

มีความแตกต่างในการสร้างไม่แน่นอนที่ว่างเปล่าที่มีค่าเริ่มต้นที่นำมาจากไม่เปลี่ยนรูป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

Caveat (ดูความคิดเห็นของ Rex Kerr): คุณจะไม่สามารถลบองค์ประกอบที่มาจากแผนที่ที่ไม่เปลี่ยนรูปได้:

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

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

3
สิ่งนี้มีประโยชน์ในบางกรณี แต่โปรดทราบว่าคุณไม่สามารถลบองค์ประกอบในแผนที่ใหม่ที่มีอยู่ในแผนที่เริ่มต้นของคุณได้ คุณสามารถปกปิดและเปิดเผยค่าเริ่มต้นเท่านั้น
Rex Kerr

ถูกต้องวิธีนี้เป็นเพียงบางส่วน
Alexander Azarov

0

ด้วย scala 2.13 มีสองทางเลือก: toวิธีการของอินสแตนซ์แผนที่ต้นทางหรือfromวิธีการของวัตถุคู่หูของแผนที่ปลายทาง

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)

อย่างที่คุณเห็นการmutable.Mapใช้งานนั้นถูกกำหนดโดยไลบรารี หากคุณต้องการที่จะเลือกดำเนินการโดยเฉพาะอย่างยิ่งตัวอย่างเช่นmutable.HashMapแทนที่เกิดขึ้นทั้งหมดด้วยmutable.Mapmutable.HashMap

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.