2014-09-03 10 views

Odpowiedz

30

Załóżmy, że mamy Map[A,B]. Dla wyjaśnienia: zawsze mam na myśli niezmienny Map.

mapValues przyjmuje funkcję B => C, gdzie C jest nowym typem wartości.

transform przyjmuje funkcję (A, B) => C, gdzie ten C jest również typem dla wartości.

Więc oba skutkują Map[A,C].

Jednak z funkcją transform możesz wpływać na wynik nowych wartości przez wartość ich kluczy.

Na przykład:

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

Robi to z mapValues będzie dość trudne.

Następną różnicą jest to, że transform jest ścisłe, natomiast mapValues daje tylko widok, który nie będzie przechowywać zaktualizowanych elementów. Wygląda to tak:

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

(zaczerpnięte z https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244)

Więc wydajność mądry to zależy od tego, co jest bardziej skuteczne. Jeśli f jest kosztowny i masz dostęp tylko do kilku elementów wynikowej mapy, mapValues może być lepszy, ponieważ f jest stosowany tylko na żądanie. W przeciwnym razie trzymałbym się map lub transform.

transform można również wyrazić za pomocą map. Zakładamy m: Map[A,B] i f: (A,B) => C, następnie

m.transform(f) jest równoważna m.map{case (a, b) => (a, f(a, b))}

8

collection.Map nie przewiduje transform: ma inny podpis modyfikowalnych i niezmiennych Maps.

$ 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 

Zmienna przekształcić mutuje w lokalu:

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) 

Więc zmienny przekształcić nie zmienia typ mapy:

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) 

... co może się zdarzyć przy konstruowaniu nowego mapa.

2

Oto kilka różnic niewymienione:

  • mapValues tworzy mapę, która nie jest możliwy do serializacji, bez wskazania, że ​​jest to tylko widok (typ jest Map[_, _], ale po prostu spróbuj wysłać jedną po drugiej stronie drutu).

  • Od mapValues jest tylko widok, każda instancja zawiera prawdziwy Map - który mógłby być inny wynik mapValues. Wyobraź sobie, że masz aktora z jakimś stanem, a każda mutacja stanu ustawia nowy stan na mapValues na poprzednim stanie ... na koniec masz głęboko zagnieżdżone mapy z kopią każdego poprzedniego stanu aktora (i tak, oba te są z doświadczenia).

Powiązane problemy