2012-07-31 12 views
24

Al concatenar dos mapas inmutables, parece que los elementos del operando de la derecha se "sobreescribir" los elementos de la izquierda:Concatenar dos mapas inmutables: ¿qué elementos se prefieren?

scala> List((1, 2), (5, 6)).toMap ++ List((5, 9)).toMap 
res13: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 5 -> 9) 

scala> List((5, 9)).toMap ++ List((1, 2), (5, 6)).toMap 
res14: scala.collection.immutable.Map[Int,Int] = Map(5 -> 6, 1 -> 2) 

Me gustaría saber, si esto es una regla en Scala?

Desde la API de Scala no pude resolver esta pregunta.

Respuesta

20

Sí, este comportamiento es constante

+2

Gracias. Si también puede decirme por qué (o dar una referencia donde se define la regla), obtendrá la respuesta aceptada. :-) –

+2

En la mayoría de los casos, la implementación de '++' se basa en '+', que a su vez se basa en 'updated' y en [this] (http://www.scala-lang.org/api/current /scala/collection/immutable/Map.html) scaladoc se afirma que 'updated' devuelve un nuevo mapa inmutable actualizado con los nuevos valores. Sí, lo sé, no es una prueba absoluta, por lo que probablemente no deberías cerrar esta pregunta aún y esperar una mejor referencia. Sin embargo, la referencia de "Mapa de Java" es bull $ hit. –

11

Map.++is defined as:

override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): immutable.Map[A, B1] = 
    ((repr: immutable.Map[A, B1]) /: xs.seq) (_ + _) 

donde repr es su mapa actual y xs.seq le da una secuencia de los pares/asignaciones almacenados en el mapa que se pasa a ++.


Map./:is described as:

def /:[B](z: B)(op: (B, (A, B)) ⇒ B): B 

Applies a binary operator to a start value and all elements of this 
immutable map, going left to right. 

Note: /: is alternate syntax for foldLeft; 
z /: xs is the same as xs foldLeft z. 

Tenga en cuenta que no se especifica qué "de izquierda a derecha" significa para un mapa desordenada.


El siguiente ejemplo ilustra lo que sucede detrás de la escena por reimplementar ++ y aumentando con depuración println declaraciones:

val m1 = Map(1 -> "A", 2 -> "B", 3 -> "C") 
val m2 = Map(2 -> "X", 3 -> "Y", 4 -> "Z") 

println(m1.repr) 
    /* Map(1 -> A, 2 -> B, 3 -> C) */ 
println(m1.repr.getClass.getName) 
    /* scala.collection.immutable.Map$Map3 */ 

def ++[K, V](ts: Map[K, V], xs: Map[K, V]): Map[K, V] = 
    (ts /: xs) {case (acc, entry) => 
       println("acc = " + acc) 
       println("entry = " + entry) 
       acc + entry 
       } 

val m3 = ++(m1, m2) 
    /* 
    acc = Map(1 -> A, 2 -> B, 3 -> C) 
    entry = (2,X) 
    acc = Map(1 -> A, 2 -> X, 3 -> C) 
    entry = (3,Y) 
    acc = Map(1 -> A, 2 -> X, 3 -> Y) 
    entry = (4,Z) 
    */ 

println(m3) 
    /* Map(1 -> A, 2 -> X, 3 -> Y, 4 -> Z) */ 
+0

en su método ++, no obtendrá xs.seq como explicó anteriormente. ¿Por qué es esto? – Felix

+0

@Felix 'inmutable.Map' anula' def seq' para volver a sí mismo, es decir, 'this',' xs.seq' por lo tanto evalúa al mismo mapa como 'xs'. Supongo que se podría anular 'def seq' en las subclases, pero no conozco lo suficiente el diseño interno de la biblioteca de colecciones para ver cuándo sería útil o incluso necesario. –