2014-09-03 28 views

Trả lời

30

Giả sử chúng tôi có một số Map[A,B]. Để làm rõ: Tôi luôn luôn đề cập đến một bất biến Map.

mapValues có chức năng B => C, trong đó C là loại mới cho giá trị.

transform có chức năng (A, B) => C, trong đó C cũng là loại cho giá trị.

Vì vậy, cả hai kết quả sẽ là Map[A,C].

Tuy nhiên, với chức năng transform bạn có thể ảnh hưởng đến kết quả của các giá trị mới bằng giá trị khóa của chúng.

Ví dụ:

val m = Map("a" -> 2, "b" -> 3) 
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3) 

Việc làm này với mapValues sẽ khá khó khăn.

Sự khác biệt tiếp theo là transform là nghiêm ngặt, trong khi mapValues sẽ chỉ cung cấp cho bạn chế độ xem, chế độ này sẽ không lưu trữ các phần tử được cập nhật. Nó trông giống như thế này:

protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] { 
    override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v))) 
    def iterator = for ((k, v) <- self.iterator) yield (k, f(v)) 
    override def size = self.size 
    override def contains(key: A) = self.contains(key) 
    def get(key: A) = self.get(key).map(f) 
} 

(lấy từ https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244)

Vì vậy, hiệu suất-khôn ngoan nó phụ thuộc những gì là hiệu quả hơn. Nếu f là tốn kém và bạn chỉ truy cập vào một số yếu tố của bản đồ kết quả, mapValues có thể tốt hơn, vì f chỉ được áp dụng theo yêu cầu. Nếu không, tôi sẽ dính vào map hoặc transform.

transform cũng có thể được thể hiện bằng map. Giả m: Map[A,B]f: (A,B) => C, sau đó

m.transform(f) tương đương với m.map{case (a, b) => (a, f(a, b))}

8

collection.Map không cung cấp transform: nó có một chữ ký khác nhau cho Maps có thể thay đổi và không thay đổi.

$ scala 
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> val im = Map('a -> 1, 'b -> 2, 'c -> 3) 
im: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 1, 'b -> 2, 'c -> 3) 

scala> im.mapValues(_ * 7) eq im 
res0: Boolean = false 

scala> im.transform { case (k,v) => v*7 } eq im 
res2: Boolean = false 

scala> val mm = collection.mutable.Map('a -> 1, 'b -> 2, 'c -> 3) 
mm: scala.collection.mutable.Map[Symbol,Int] = Map('b -> 2, 'a -> 1, 'c -> 3) 

scala> mm.mapValues(_ * 7) eq mm 
res3: Boolean = false 

scala> mm.transform { case (k,v) => v*7 } eq mm 
res5: Boolean = true 

Biên Đổi thay đổi đột biến tại chỗ:

scala> mm.transform { case (k,v) => v*7 } 
res6: mm.type = Map('b -> 98, 'a -> 49, 'c -> 147) 

scala> mm.transform { case (k,v) => v*7 } 
res7: mm.type = Map('b -> 686, 'a -> 343, 'c -> 1029) 

Vì vậy, có thể thay đổi chuyển đổi không làm thay đổi loại bản đồ:

scala> im mapValues (_ => "hi") 
res12: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi) 

scala> mm mapValues (_ => "hi") 
res13: scala.collection.Map[Symbol,String] = Map('b -> hi, 'a -> hi, 'c -> hi) 

scala> mm.transform { case (k,v) => "hi" } 
<console>:9: error: type mismatch; 
found : String("hi") 
required: Int 
       mm.transform { case (k,v) => "hi" } 
             ^

scala> im.transform { case (k,v) => "hi" } 
res15: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi) 

... như có thể xảy ra khi xây dựng mới bản đồ.

2

Dưới đây là một vài sự khác biệt không được đề cập:

  • mapValues tạo ra một bản đồ đó là KHÔNG serializable, mà không cần bất kỳ dấu hiệu cho thấy nó chỉ là một cái nhìn (loại là Map[_, _], nhưng chỉ cần cố gắng gửi một trên dây).

  • Kể từ mapValues chỉ là một cái nhìn, mỗi trường hợp có chứa các thực Map-mà có thể là một kết quả của mapValues. Hãy tưởng tượng bạn có một diễn viên với một số trạng thái và mọi đột biến của trạng thái sẽ đặt trạng thái mới là mapValues ở trạng thái trước đó ... cuối cùng bạn có bản đồ lồng nhau sâu với bản sao của mỗi trạng thái trước đó của tác nhân (và , vâng, cả hai đều từ kinh nghiệm).

Các vấn đề liên quan