web-dev-qa-db-fra.com

Scala: mapper une carte à la liste des tuples

J'ai essayé d'utiliser Map.map pour convertir une carte en une liste de tuples. Mais cela échoue. J'ai fait les expériences suivantes:

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

Remarquez comment une liste est générée pour les éléments simples (r1) mais une carte est produite pour les tuples (r3). Pas même forcer le type travaillé (r2). Seul un appel explicite à Seq l'a fait (r4) Donc ma question est, pourquoi/comment Map.map crée-t-il "automagiquement" une nouvelle carte et pas une liste par exemple? En fait, comment le type de retour est-il déterminé (Seq, List, etc.)

14
user2051561

Un Map est déjà une collection de tuples.

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

Lorsque vous mappez un Map, vous mappez les paires (clé, valeur) qu'il contient. Cela ne peut pas fonctionner, car vous supprimez les clés et ne conservez que les valeurs. Donc, ce que vous avez n'est plus un Map, mais une étape ou deux dans la hiérarchie de la collection, un Iterable:

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

Forcer le type ne peut pas fonctionner, car un Map[A, B] N'est pas un List[(A, B)]. C'est l'équivalent de m.map(identity). Remarquez comment vous accédez même à e avec des accesseurs Tuple:

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

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

Ici, Seq est plus généralisé que List:

val r4 = m.toSeq

La solution simple indiquée par @EndeNeu consiste à utiliser simplement toList. Lorsque vous map une collection, elle doit renvoyer le type de collection d'origine si elle le peut. Ainsi, le mappage d'un Map devrait renvoyer un autre Map, à moins que la structure sous-jacente ne l'ait plus transformé en Map (comme la suppression de clés entièrement) dans r1.

23
Michael Zajac