2012-07-31 10 views
24

Quando concatenare due mappe immutabili, sembra che gli elementi del operando di destra saranno "sovrascrivere" gli elementi di quella di sinistra:Concatena due mappe immutabili: quali elementi sono preferiti?

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) 

Vorrei sapere, se questa è una regola a Scala?

Dall'API di Scala non sono riuscito a capire questa domanda.

risposta

20

Sì, questo comportamento è costante

+2

Grazie. Se puoi anche dirmi perché (o dare un riferimento dove la regola è definita), otterrai la risposta accettata. :-) –

+2

Nella maggior parte dei casi l'implementazione di '++' dipende da '+', che a sua volta si basa su 'updated' e in [this] (http://www.scala-lang.org/api/current /scala/collection/immutable/Map.html) scaladoc si afferma che 'updated' restituisce una nuova mappa immutabile aggiornata con i nuovi valori. Sì, lo so, non una prova assoluta, quindi probabilmente non dovresti chiudere ancora questa domanda e aspettare un riferimento migliore. Tuttavia, il riferimento "Mappa Java" è toro di successo. –

11

Map.++is defined as:

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

dove repr è la mappa corrente e xs.seq ti dà una sequenza di accoppiamenti/mappature memorizzate nella mappa si passa 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. 

Nota che non è specificato che cosa "da sinistra a destra" si intende per una mappa non ordinato.


Di seguito illustra ciò che accade dietro le quinte da reimplementare ++ e aumentando con il debug println dichiarazioni:

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

nel tuo metodo ++, non stai ricevendo xs.seq come hai spiegato prima. Perchè è questo? – Felix

+0

@Felix 'immutable.Map' sovrascrive' def seq' per restituire se stesso, ad esempio 'this',' xs.seq' quindi valuta la stessa mappa di 'xs'. Suppongo che uno possa sovrascrivere 'def seq' in sottoclassi, ma non conosco abbastanza il design interno della libreria delle collezioni per vedere quando sarebbe utile o addirittura necessario. –

Problemi correlati