我有一个RDD列表[(String,List [Int])]像List((“ A”,List(1,2,3,4)),(“ B”,List(5,6,7 )))
如何将它们转换为List((“ A”,1),(“ A”,2),(“ A”,3),(“ A”,4),(“ B”,5), (“ B”,6),(“ B”,7))
然后操作将是通过键减少并生成类似List((“ A”,2.5)(“ B”,6))
的结果我已经尝试过使用map(e => List(e._1,e._2)),但没有得到想要的结果。
其中“ A”平均为2.5,而“ B”平均为6
通过这些转换和操作帮助我。 预先感谢
答案 0 :(得分:1)
有几种获取所需内容的方法。您也可以使用for comprehension,但我想到的第一个方法是此实现:
val l = List(("A", List(1, 2, 3)), ("B", List(1, 2, 3)))
val flattenList = l.flatMap {
case (elem, _elemList) =>
_elemList.map((elem, _))
}
输出:
List((A,1), (A,2), (A,3), (B,1), (B,2), (B,3))
答案 1 :(得分:1)
如果您想要的是最后每个列表的平均值,则没有必要使用flatMap
将它们分解为单个元素。如果使用大列表,则不必要地使用大数据集对大量数据进行混洗。
由于它们已经通过键进行聚合,因此只需使用以下内容对其进行转换:
val l = spark.sparkContext.parallelize(Seq(
("A", List(1, 2, 3, 4)),
("B", List(5, 6, 7))
))
val avg = l.map(r => {
(r._1, (r._2.sum.toDouble / r._2.length.toDouble))
})
avg.collect.foreach(println)
请记住,如果您的任何列表的长度为0
,此操作都会失败。如果您有一些0
长度列表,则必须在地图中放置一个检查条件。
上面的代码为您提供:
(A,2.5)
(B,6.0)
答案 2 :(得分:1)
您可以尝试explode()
scala> val df = List(("A",List(1,2,3,4)),("B",List(5,6,7))).toDF("x","y")
df: org.apache.spark.sql.DataFrame = [x: string, y: array<int>]
scala> df.withColumn("z",explode('y)).show(false)
+---+------------+---+
|x |y |z |
+---+------------+---+
|A |[1, 2, 3, 4]|1 |
|A |[1, 2, 3, 4]|2 |
|A |[1, 2, 3, 4]|3 |
|A |[1, 2, 3, 4]|4 |
|B |[5, 6, 7] |5 |
|B |[5, 6, 7] |6 |
|B |[5, 6, 7] |7 |
+---+------------+---+
scala> val df2 = df.withColumn("z",explode('y))
df2: org.apache.spark.sql.DataFrame = [x: string, y: array<int> ... 1 more field]
scala> df2.groupBy("x").agg(sum('z)/count('z) ).show(false)
+---+-------------------+
|x |(sum(z) / count(z))|
+---+-------------------+
|B |6.0 |
|A |2.5 |
+---+-------------------+
scala>