Làm cách nào để chuyển đổi Immutable.Map sang mutable.Map trong Scala?


93

Làm cách nào tôi có thể chuyển đổi immutable.Mapsang mutable.Maptrong Scala để có thể cập nhật các giá trị trong Map?

Câu trả lời:


126

Cách sạch sẽ nhất là sử dụng mutable.Mapnhà máy sản xuất kỳ đà . Không giống như ++cách tiếp cận, cách này sử dụng CanBuildFromcơ chế và do đó có khả năng hiệu quả hơn nếu mã thư viện được viết để tận dụng lợi thế này:

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

Điều này hoạt động vì a Mapcũng có thể được xem như một chuỗi các Cặp.


2
Bạn có thể giải thích, bạn sử dụng cú pháp nào trong dòng thứ hai khi truyền tham số? Dấu hai chấm có chức năng gì?
Heinzi

7
: _*giống như kiểu ký tự, cho trình biên dịch biết chính xác kiểu cần gán cho một biểu thức nhất định. Bạn có thể nghĩ về nó ở đây như nói "lấy chuỗi này và coi nó như một số tham số vararg."
Kevin Wright

16
Có gì đó sai với các thư viện bộ sưu tập nếu đây là thư viện sạch nhất;)
matanster

2
@ Matt Nó có thể được thực hiện ngắn hơn một chút với hàng nhập khẩu aliased, nhưng nhớ rằng phải hy sinh tính bất biến là rất phi ngữ cho Scala, không chính xác các loại điều tôi muốn enourage bằng cách làm cho nó trông thậm chí còn dễ dàng hơn ... Ra khỏi tò mò , làm thế nào khác bạn có thể đề xuất làm điều đó một cách sạch sẽ hơn, nếu không thông qua một bản sao?
Kevin Wright

Đó là quan điểm của tôi, tôi không thể, nhưng một thư viện bộ sưu tập tốt hơn có thể biến điều này thành hiện thực, IMHO.
matanster

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

1
Bạn có biết độ phức tạp thời gian tiệm cận của điều này là không? Tôi biết rằng Clojure có thể biến bất kỳ bộ sưu tập liên tục nào của nó thành bộ sưu tập "nhất thời" (tức là bộ có thể thay đổi với các hàm đột biến được định kiểu tuyến tính) và trở lại thành bộ liên tục theo O(1)từng bước. Điều này có vẻ như vậy O(n), mặc dù điều đó tất nhiên phụ thuộc vào mức độ thông minh của việc triển khai ++.
Jörg W Mittag

1
@ Jörg - Tôi khá chắc chắn là cái này O(n). Trong giới hạn khi bạn thay đổi mọi thứ, điều đó phải xảy ra O(n), mặc dù bạn có thể cố gắng trì hoãn việc tạo bản sao mới để tiết kiệm thời gian hoặc bạn tăng gấp đôi thời gian truy cập của mình bằng cách đọc các tập thay đổi thay vì bản đồ gốc. Cái nào hoạt động tốt nhất có lẽ phụ thuộc vào trường hợp sử dụng của bạn.
Rex Kerr

1
@Rustem - Bản đồ không có thứ tự. Chúng sẽ xuất hiện theo bất kỳ thứ tự nào mà chúng cảm thấy thích (với bản đồ băm, đó thường là thứ tự của khóa băm). Đặc biệt, bản đồ bất biến có những trường hợp đặc biệt dành cho bản đồ thực sự nhỏ khác với bản đồ có thể thay đổi.
Rex Kerr

@Rustem Maps không được đặt hàng.
Daniel C. Sobral

4

Làm thế nào về việc sử dụng 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)

rất tuyệt, nhưng về cơ bản nó làm tương tự như mutable.Map#applyvới một tấm boilerplate hơn một chút.
Kevin Wright

4

Bắt đầu Scala 2.13, thông qua các nhà xây dựng nhà máy áp dụng với .to(factory):

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

1

Có một biến thể để tạo một biến thể trống có Mapcác giá trị mặc định được lấy từ bất biến Map. Bạn có thể lưu trữ một giá trị và ghi đè giá trị mặc định bất kỳ lúc nào:

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

Lưu ý (xem nhận xét của Rex Kerr): Bạn sẽ không thể xóa các phần tử đến từ bản đồ bất biến:

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

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

3
Điều này hữu ích trong một số trường hợp, nhưng lưu ý rằng bạn không thể xóa một phần tử trong bản đồ mới đã có trong bản đồ mặc định của bạn; bạn chỉ có thể che và khám phá các mặc định.
Rex Kerr

Đúng, giải pháp này là một phần.
Alexander Azarov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.