0.Scala函数式编程
我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程。下面这些事开发中常用的函数式编程。注意这些函数都是操作 Scala 集合的,一般会进行两类操作:转换操作(transformation )和行动操作(actions)(有些人喜欢叫他为聚合操作)。第一种操作类型将集合转换为另一个集合,第二种操作类型返回某些类型的值。
- 遍历( foreach )
- 映射( map )
- 映射扁平化( flatmap )
- 过滤( filter )
- 是否存在( exists )
- 排序( sorted 、 sortBy 、 sortWith )
- 分组( groupBy )
- 聚合计算( reduce )
- 折叠( fold )
1.map的使用详解
集合的映射操作是将来在编写Spark/Flink用得最多的操作,是我们必须要掌握的掌握。map方法接收一个函数,将这个函数应用到每一个元素,返回一个新的列表
【1.1语法结构】
def map[B](f: (A) ⇒ B): TraversableOnce[B]
【1.2语法解释】
尖叫提示:
- 1.同foreach一样,map传入的参数也是函数,匿名函数
- 2.map 函数的逻辑是遍历集合中的元素并对每个元素调用函数。你也可以不调用任何函数,保持返回元素本身,但这样 map无法发挥作用,因为你在映射过后得到的是同样的集合。
- 3.foreach返回值是Unit,而map返回值是集合,简单来说map就是对集合元素进行加工,不影响集合结构。
- 4.map和foreach,以及后续其他的集合函数一样,都支持类型推定和用下划线_简化函数定义。
【1.3 map使用演示】
//基础演示
val chars = Seq('a', 'b', 'c', 'd')
chars.map(ch => ch.toUpper) //输出为List(A, B, C, D)
scala> val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)
numbers: Seq[Int] = List(3, 7, 2, 9, 6, 5, 1, 4, 2)
scala> numbers.map(x=>x*x)
res4: Seq[Int] = List(9, 49, 4, 81, 36, 25, 1, 16, 4)
//注意这里打印x,最终返回的也是一个集合,只是空集合,空列表,列表结构不变
scala> numbers.map(x=>println(x))
3
7
2
9
6
5
1
4
2
res5: Seq[Unit] = List((), (), (), (), (), (), (), (), ())
//标准函数,类型推定,下划线替代
scala> a.map((x:Int)=>x+1)
res8: List[Int] = List(2, 3, 4, 5)
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> a.map(_+1)
res6: List[Int] = List(2, 3, 4, 5)
scala> a.map(x=>x+1)
res7: List[Int] = List(2, 3, 4, 5)
2.flatten的使用详解
flatten可以把嵌套的结构展开。当有一个集合的集合,然后你想对这些集合的所有元素进行操作时,就会用到 flatten。如果一个集合里存放的是元组,则没法压平,只能压平集合。flatten比较简单,没有参数。用的多是跟他名字很像的flatmap。
val abcd = List('a', 'b', 'c', 'd')
val efgj = List('e', 'f', 'g', 'h')
val ijkl = List('i', 'j', 'k', 'l')
val mnop = List('m', 'n', 'o', 'p')
val qrst = List('q', 'r', 's', 't')
val uvwx = List('u', 'v', 'w', 'x')
val yz = List('y', 'z')
val alphabet = Seq(abcd, efgj, ijkl, mnop, qrst, uvwx, yz)
println(alphabet.flatten)
//结果:// ArrayBuffer(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)
//必须是集合的集合才能flatte,同时里面的集合不能是元组,否则也无法flatten。
scala> val abc = List((1,2),(3,4))
abc: List[(Int, Int)] = List((1,2), (3,4))
scala> abc.flatten
<console>:13: error: No implicit view available from (Int, Int) => scala.collection.GenTraversableOnce[B].
abc.flatten
^
scala> val abc= List(1,2,3)
abc: List[Int] = List(1, 2, 3)
scala> abc.flatten
<console>:13: error: No implicit view available from Int => scala.collection.GenTraversableOnce[B].
abc.flatten
^
3.flatMap的使用详解
flatMap结合了map和flatten的功能。接收一个可以处理嵌套列表的函数,然后把返回结果连接起来。可以把flatMap,理解为先map,然后再flatten
【3.1语法结构】
def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): TraversableOnce[B]
flatMap使用流程:如下,对List内部成员先进行map,map的结果为一个返回,然后在返回的新List结果上进行flatten扁平化。简单理解就是flatmap可以拆分成map+flatten
【尖叫提示】
- 1.因为flatMap有flatten的操作所以flatMap的调用对象必须是集合的集合,要满足flatten的要求
- 2.flatMap实际操作中就是可以转化成map函数+flatten函数一起操作,只是前者代码更加简洁
//1.使用map+flat
scala> val fm = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
fm: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)
scala> fm.map(x => x.split(" "))
res14: List[Array[String]] = List(Array(hadoop, hive, spark, flink, flume), Array(kudu, hbase, sqoop, storm))
scala> res14.flatten
res15: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
scala> fm.map(x => x.split(" ")).flatten
res18: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
//2.直接使用flatMap
scala> fm.flatMap(x => x.split(" "))
res23: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
scala> fm.flatMap(_.split(" "))
res20: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)