Convertir la liste de tuple en carte (et gérer la clé en double?)

Je pensais à une belle façon de convertir une liste de tuple avec une clé en double [("a","b"),("c","d"),("a","f")] en carte ("a" -> ["b", "f"], "c" -> ["d"]) . Normalement (en python), je créerais une carte vide et une boucle en boucle sur la liste et vérifierais si une clé est en double. Mais je cherche quelque chose de plus scala-ish et de solution intelligente ici.

btw, le type réel de valeur-clé que j’utilise ici est (Int, Node) et je veux me transformer en une carte de (Int -> NodeSeq)

Grouper puis projeter:

 scala> val x = List("a" -> "b", "c" -> "d", "a" -> "f") //x: List[(java.lang.Ssortingng, java.lang.Ssortingng)] = List((a,b), (c,d), (a,f)) scala> x.groupBy(_._1).map { case (k,v) => (k,v.map(_._2))} //res1: scala.collection.immutable.Map[java.lang.Ssortingng,List[java.lang.Ssortingng]] = Map(c -> List(d), a -> List(b, f)) 

Une manière plus évolutive d’utiliser les plis, comme ici (passer l’étape de la map f ).

Pour les Googlers qui ne s’attendent pas à des doublons ou à la règle de gestion des doublons par défaut :

 List("a" -> 1, "b" -> 2).toMap // Result: Map(a -> 1, c -> 2) 

À partir de 2.12, la stratégie par défaut se lit comme suit:

Les clés en double seront écrasées par des clés ultérieures: s’il s’agit d’une collection non ordonnée, la clé figurant dans la carte résultante n’est pas définie.

Voici une autre alternative:

 x.groupBy(_._1).mapValues(_.map(_._2)) 

Pour les Googlers qui se soucient des doublons:

 implicit class Pairs[A, B](p: List[(A, B)]) { def toMultiMap: Map[A, List[B]] = p.groupBy(_._1).mapValues(_.map(_._2)) } > List("a" -> "b", "a" -> "c", "d" -> "e").toMultiMap > Map("a" -> List("b", "c"), "d" -> List("e")) 

Voici un moyen plus idiomatique Scala de convertir une liste de tuples en une carte gérant des clés en double. Vous voulez utiliser un pli.

 val x = List("a" -> "b", "c" -> "d", "a" -> "f") x.foldLeft(Map.empty[Ssortingng, Seq[Ssortingng]]) { case (acc, (k, v)) => acc.updated(k, acc.getOrElse(k, Seq.empty[Ssortingng]) ++ Seq(v)) } res0: scala.collection.immutable.Map[Ssortingng,Seq[Ssortingng]] = Map(a -> List(b, f), c -> List(d)) 

Vous trouverez ci-dessous quelques solutions. (GroupBy, FoldLeft, Aggregate, Spark)

 val list: List[(Ssortingng, Ssortingng)] = List(("a","b"),("c","d"),("a","f")) 

GroupBy variation

 list.groupBy(_._1).map(v => (v._1, v._2.map(_._2))) 

Variation de pli gauche

 list.foldLeft[Map[Ssortingng, List[Ssortingng]]](Map())((acc, value) => { acc.get(value._1).fold(acc ++ Map(value._1 -> List(value._2))){ v => acc ++ Map(value._1 -> (value._2 :: v)) } }) 

Variation d’agrégat – similaire au pli gauche

 list.aggregate[Map[Ssortingng, List[Ssortingng]]](Map())( (acc, value) => acc.get(value._1).fold(acc ++ Map(value._1 -> List(value._2))){ v => acc ++ Map(value._1 -> (value._2 :: v)) }, (l, r) => l ++ r ) 

Variation Spark – Pour les ensembles de données volumineuses (conversion en RDD et en une carte simple à partir de RDD)

 import org.apache.spark.rdd._ import org.apache.spark.{SparkContext, SparkConf} val conf: SparkConf = new SparkConf().setAppName("Spark").setMaster("local") val sc: SparkContext = new SparkContext (conf) // This gives you a rdd of the same result val rdd: RDD[(Ssortingng, List[Ssortingng])] = sc.parallelize(list).combineByKey( (value: Ssortingng) => List(value), (acc: List[Ssortingng], value) => value :: acc, (accLeft: List[Ssortingng], accRight: List[Ssortingng]) => accLeft ::: accRight ) // To convert this RDD back to a Map[(Ssortingng, List[Ssortingng])] you can do the following rdd.collect().toMap 

Vous pouvez essayer ceci

 scala> val b = new Array[Int](3) // b: Array[Int] = Array(0, 0, 0) scala> val c = b.map(x => (x -> x * 2)) // c: Array[(Int, Int)] = Array((1,2), (2,4), (3,6)) scala> val d = Map(c : _*) // d: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 4, 3 -> 6)