2015-02-27 20 views
10

Ho provato a utilizzare Map.map per convertire una mappa in un elenco di tuple. Tuttavia questo fallisce. Ho fatto i seguenti esperimenti:Scala: mappa a Mappa per elenco tuple

val m = Map(("a" -> 1), ("b" -> 2)) 
     //> m :  scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2) 
val r1 = m.map{ case (k,v) => v}    //> r1 : scala.collection.immutable.Iterable[Int] = List(1, 2) 
def toTuple[A,B](a:A,b:B) = (a,b)    //> toTuple: [A, B](a: A, b: B)(A, B) 
//val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2)) 
val r3 = m.map(e => toTuple(e._1,e._2))   //> r3 : scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2) 
val r4 = m.toSeq        //> r4 : Seq[(String, Int)] = ArrayBuffer((a,1), (b,2)) 

Si noti come una lista è generato per singoli elementi (R1), ma una mappa viene prodotto per le tuple (r3). Non forzare nemmeno il tipo lavorato (r2). Solo una chiamata esplicita a Seq l'ha fatto (r4) Quindi la mia domanda è: perché/come Map.map "automagicamente" crea una nuova mappa e non una lista per esempio? Infatti come è il tipo di reddito determinato (Seq, List, ecc)

+6

Cosa c'è di sbagliato in 'm.toList'? Si noti inoltre che il mapping su una raccolta restituisce un'altra raccolta dello stesso tipo, quindi non è possibile restituire una mappatura di lista su una 'Mappa ', a meno che non si chiami' .toList' su di essa. –

+0

@Ende - Niente è sbagliato. Vedi il commento qui sotto. – user2051561

risposta

14

Un Map è un insieme di tuple già.

scala> "b" -> 2 
res0: (String, Int) = (b,2) // Implicitly converted to a Tuple 

Quando sei la mappatura di un Map, si sta mappando le coppie (chiave, valore) che esso contiene. Questo non può funzionare, perché stai rimuovendo le chiavi e mantenendo solo i valori. Quindi, quello che hai non è più una Map, ma un passo o due nella gerarchia di raccolta, un Iterable:

val r1 = m.map{ case (k,v) => v} 

Forzare il tipo non può funzionare, perché un Map[A, B] non è un List[(A, B)]. Questo è l'equivalente di m.map(identity). Notate come si sta ancora accedendo e con funzioni di accesso tuple:

val r2: List[Tuple2[_,_]] = m.map(e => (e._1,e._2)) 

val r3 = m.map(e => toTuple(e._1,e._2)) 

Qui, Seq è più generalizzata di List:

val r4 = m.toSeq 

La soluzione semplice quanto affermato dal @EndeNeu è usare solo toList. Se hai una collezione map, dovrebbe restituire il tipo di raccolta originale, se possibile. Pertanto, la mappatura di Map deve restituire un altro Map, a meno che la struttura sottostante non lo abbia reso più un Map (come la rimozione completa delle chiavi) in r1.

+0

Grazie m-z. La mia domanda è davvero: nel caso di 'r1', in che modo' Map' sa che dovrebbe convertirsi in un 'List'? Potrebbe essere qualcos'altro? Perché non un array? Presumo che la loro conversione implicita avvenga qui. Quindi il mio test forzando i tipi. Per quanto riguarda le tuple, ha senso. Questa è la convenzione della mappa. – user2051561

+0

@ user2051561 Non lo converte in un 'List' in' r1' - restituisce 'Iterable' perché quello è il tratto successivo più vicino alla gerarchia che corrisponde al tipo di collezione che si ha. 'Map' estende' Iterable'. –