我的档案是,
sunny,hot,high,FALSE,no
sunny,hot,high,TRUE,no
overcast,hot,high,FALSE,yes
rainy,mild,high,FALSE,yes
rainy,cool,normal,FALSE,yes
rainy,cool,normal,TRUE,no
overcast,cool,normal,TRUE,yes
这里有7排& 5列(0,1,2,3,4)
我希望输出为,
Map(0 -> Set("sunny","overcast","rainy"))
Map(1 -> Set("hot","mild","cool"))
Map(2 -> Set("high","normal"))
Map(3 -> Set("false","true"))
Map(4 -> Set("yes","no"))
输出必须是[Map [Int,Set [String]]]
的类型答案 0 :(得分:4)
编辑:重写以首先展示map-reduce版本,因为它更适合Spark
由于这是Spark,我们可能对并行/分发感兴趣。所以我们需要注意启用它。
将每个字符串拆分为单词可以在分区中完成。获取每列中使用的值集更加棘手 - 初始化集合然后添加每行中的每个值的天真方法本质上是串行/本地,因为我们只有一组(每列)&# 39;重新添加每行的值。
但是,如果我们为行的某些部分设置了集合,而为其余部分设置了集合,那么答案就是这些集合的并集。这表示减少操作,我们合并行的某些子集的集合,然后合并这些,依此类推,直到我们有一个集合。
所以,算法:
我们做地图然后是减少并不是巧合,这应该提醒你一些事情:)
这是一个产生单行的单行:
val data = List(
"sunny,hot,high,FALSE,no",
"sunny,hot,high,TRUE,no",
"overcast,hot,high,FALSE,yes",
"rainy,mild,high,FALSE,yes",
"rainy,cool,normal,FALSE,yes",
"rainy,cool,normal,TRUE,no",
"overcast,cool,normal,TRUE,yes")
val row = data.map(_.split("\\W+").map(s=>Set(s)))
.reduce{(a, b) => (a zip b).map{case (l, r) => l ++ r}}
将问题转换为地图,问题是:
val theMap = row.zipWithIndex.map(_.swap).toMap
这些不需要更改AT ALL以与Spark一起使用。我们只需要使用RDD而不是List。让我们将数据转换为RDD只是为了演示这个:
val conf = new SparkConf().setAppName("spark-scratch").setMaster("local")
val sc= new SparkContext(conf)
val rdd = sc.makeRDD(data)
val row = rdd.map(_.split("\\W+").map(s=>Set(s)))
.reduce{(a, b) => (a zip b).map{case (l, r) => l ++ r}}
(这可以像以前一样转换成地图)
早期的oneliner工作得很整齐(转置正是这里所需要的)但很难分发(转置本身就需要访问每一行)
data.map(_.split("\\W+")).transpose.map(_.toSet)
(为清晰起见省略转换为地图)
答案 1 :(得分:1)
也许这就是诀窍:
val a = Array(
"sunny,hot,high,FALSE,no",
"sunny,hot,high,TRUE,no",
"overcast,hot,high,FALSE,yes",
"rainy,mild,high,FALSE,yes",
"rainy,cool,normal,FALSE,yes",
"rainy,cool,normal,TRUE,no",
"overcast,cool,normal,TRUE,yes")
val b = new Array[Map[String, Set[String]]](5)
for (i <- 0 to 4)
b(i) = Map(i.toString -> (Set() ++ (for (s <- a) yield s.split(",")(i))) )
println(b.mkString("\n"))