转换映射元组列表(并处理重复键?)

我正在想一个很好的方法来转换一个重复键[("a","b"),("c","d"),("a","f")]的元组列表映射("a" -> ["b", "f"], "c" -> ["d"]) 。 通常(在Python中),我会创build一个空的映射,并在列表中for循环,并检查重复键。 但是我在这里寻找更多可靠的解决scheme和巧妙的解决scheme。

顺便说一句,我在这里使用的键值的实际types是(Int, Node) ,我想变成一个映射(Int -> NodeSeq)

组然后项目:

 scala> val x = List("a" -> "b", "c" -> "d", "a" -> "f") //x: List[(java.lang.String, java.lang.String)] = 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.String,List[java.lang.String]] = Map(c -> List(d), a -> List(b, f)) 

更多的折叠方式使用折叠,就像那里的方式(跳过map f步骤)。

对于不要求重复或者违反默认重复处理政策的 Google员工:

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

从2.12开始,默认的策略是:

重复的键将被后面的键覆盖:如果这是一个无序的集合,那么结果映射中的哪个键是未定义的。

这是另一种select:

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

对于关心重复的Google员工:

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

下面是一个更加Scala惯用的方法来将元组列表转换为处理重复键的映射。 你想用折叠。

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

你可以试试这个

 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) 

下面你可以find一些解决scheme。 (GroupBy,FoldLeft,Aggregate,Spark)

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

组变异

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

折叠左变异

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

聚合变化 – 类似于向左折叠

 list.aggregate[Map[String, List[String]]](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 ) 

Spark Variation – 对于大数据集(从RDD转换到RDD和Plain Map)

 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[(String, List[String])] = sc.parallelize(list).combineByKey( (value: String) => List(value), (acc: List[String], value) => value :: acc, (accLeft: List[String], accRight: List[String]) => accLeft ::: accRight ) // To convert this RDD back to a Map[(String, List[String])] you can do the following rdd.collect().toMap