(一)


因为Spark很多语法及其思想都是借鉴Scala的,所以我们先看看 Scala中map()与flatMap()函数的区别,其中顺便介绍flatten方法:


(a)



使用flatten方法把一个包含列表的列表转变为一个单列表。



  • 创建列表的列表:


scala> val lol = List(List(1,2), List(3,4)) 
 
  
      lol: List[List[Int]] = List(List(1, 2), List(3, 4))



  • 在列表的列表上调用flatten方法创建一个新列表: 


scala> val result = lol.flatten
 
  
      result: List[Int] = List(1, 2, 3, 4)



则,flatten将包含列表的列表展平为一个结果列表。






flatten方法不仅限于列表,还可以用于其他序列 (Array、 ArrayBuffer、 Vector等):

scala> val a = Array(Array(1,3), Array(2,4))
 
  
a: Array[Array[Int]] = Array(Array(1, 3), Array(2, 4))





scala> a.flatten
 
  
res0: Array[Int] = Array(1, 3, 2, 4)



flatten方法在至少其他两种场景很有用。第一,因为字符串是字符的序列,可以把字符串的列表转变为一个字符的列表(字符串的列表--> 字符的列表):




scala> val list = List("Hello", "world")
 
 
list: List[String] = List(Hello, world)
 
 

 
 
scala> list.flatten
 
 
res1: List[Char] = List(H, e, l, l, o, w, o, r, l, d)






第二,因为Option可以被看作是包含零个或者一个元素的容器,flatten对于Some和None元素的序列很有用。它会将Some中的值取出来新建一个列表,然后丢掉None元素(flatten--> kill None):






scala> val x = Vector(Some(1), None, Some(3), None)
 
 
x: scala.collection.immutable.Vector[Option[Int]] = Vector(Some(1), None, Some(3), None)
 
 

 
 
scala> x.flatten
 
 
res2: scala.collection.immutable.Vector[Int] = Vector(1, 3)


(b)



问题:对于flatMap方法,如何使用它?哪里使用它?



当在map后需要使用flatten时使用flatMap。具体情况是:



  • 在使用map方法(或者for/yield表达式)根据一个已有的集合创建一个新的集合。
  • 结果集合是一个列表的列表。
  • 可以在map(或者一个for/yield表达式)后立刻调用flatten。



当遇到这些情况时,可以使用flatMap。...通用法则:无论何时想要在map后调用flatten,就用flatMap。




(二)


spark中的map和flatMap区别如上述描述类似。附图解释:








(三)


曾经遇到一个bug:


value sortByKey is not a member of org.apache.spark.rdd.RDD[scala.collection.immutable.Map[Double,(scala.collection.immutable.Set[Int], Int)]]




原因是因为 sortByKey应该适用于如下类型的:

scala> val oneFIS = rawTrans.flatMap(line=>line).map((_,1))
 
oneFIS: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[4] at map at <console>:28

即sortByKey()适用于RDD[(k, v)]这种类型,而不是RDD[Map[k, v]]这种类型;不然会提示value sortByKey is not a member of org.apache.spark.rdd.RDD[Map[k, v]]之类的错误。


所以,只要将代码中的map修改为flatMap即可!这算是使用map和使用flatMap的一个场景区别罢!




主要参考:《Spark快速大数据分析》、《Scalabianch》