5 scala的函数式编程简介
与Java一样,Scala 也是使用 Lambda
表达式实现函数式变成的。
1 遍历
除了使用 for
可以对数组、List
、Set
进行遍历外,也可以使用 foreach
函数式编程进行遍历,使代码更为简洁。
foreach
的方法签名为:
foreach(f: (A) => Unit): Unit
- 参数:接受一个函数对象,函数的输入参数为集合的元素。
例如:
scala> List("C朗", "美斯", "云尼").foreach(p => println(p))
C朗
美斯
云尼
2 下划线简化函数定义
如果符合下面两个条件,则可以使用下划线 _
代替 函数入参
简化函数定义:
(1) 函数的入参,只在函数体中出现一次。
(2) 函数体中没有嵌套调用。
例如,下面使用 _
简化了函数体定义,使代码更加简洁:
scala> List("C朗", "美斯", "云尼").foreach(p => println(p))
C朗
美斯
云尼
scala> List("C朗", "美斯", "云尼").foreach(println(_))
C朗
美斯
云尼
3 映射 map
如果要遍历集合中的每一个元素,并经过一个函数处理后生成新的元素,则可以使用集合的 map
方法。
map
方法签名为:
def map[元素类型](f: (I) => R): TraversableOnce[R]
下面例子中,定义一个 List
对象,并使每一个元素都加 1:
scala> val list = List(0,1,2,3)
val list: List[Int] = List(0, 1, 2, 3)
scala> list.map(x=>x+1)
val res24: List[Int] = List(1, 2, 3, 4)
同样,可以使用下划线简化函数定义:
scala> val list = List(0,1,2,3)
val list: List[Int] = List(0, 1, 2, 3)
scala> list.map(_+1)
val res25: List[Int] = List(1, 2, 3, 4)
4 扁平化映射
使用集合的 flatMap
方法实现扁平化映射。
可以把 flatMap
理解为先进行 map
操作,再进行 flatten
操作,即将列表中的元素转换成 List
,然后再把 List
类型的元素展开。
flatMap
的方法签名为:
def flatMap[元素类型](f: (I) => GenTraversableOnce[R]): TraversableOnce[R]
例如,一个 List
中每个元素为一行数据,每行数据内容为多个球员名字,每个球员名字用空格分隔,现在如果要统计这个 List
中一共有多少个球员,可使用 map
+ flatten
实现:
scala> var players = List("美斯 C朗", "C朗 姆总")
var players: List[String] = List(美斯 C朗, C朗 姆总)
scala> players.map(_.split(" ")).flatten
val res27: List[String] = List(美斯, C朗, C朗, 姆总)
scala> players.map(_.split(" ")).flatten.distinct
val res28: List[String] = List(美斯, C朗, 姆总)
scala> players.map(_.split(" ")).flatten.distinct.length
val res29: Int = 3
也可以直接使用 flatMap
方法实现 map
+ flatten
的效果:
scala> var players = List("美斯 C朗", "C朗 姆总")
var players: List[String] = List(美斯 C朗, C朗 姆总)
scala> players.flatMap(_.split(" "))
val res30: List[String] = List(美斯, C朗, C朗, 姆总)
scala> players.flatMap(_.split(" ")).distinct
val res31: List[String] = List(美斯, C朗, 姆总)
scala> players.flatMap(_.split(" ")).distinct.length
val res32: Int = 3
5 过滤
使用 filter
方法,可以过滤符合一定条件的元素,并返回元素 List
。
filter
的方法签名为:
def filter(f: (I) => Boolean): TraversableOnce[I]
f: (I) => Boolean
传入集合的元素,返回布尔类型变量,如果满足条件则返回 true
, 否则返回 false
。
例如,一个保存数字的 List
,只保留大于50的元素:
scala> List(90,88,33,44,50,55).filter(_ > 50)
val res33: List[Int] = List(90, 88, 55)
6 排序
Scala 的集合提供了 3 中排序方式:
- 默认排序
- 指定字段排序
- 自定义排序
6.1 默认排序
List
的 sorted
方法会对元素进行升序排列:
scala> List(90,88,33,44,50,55).sorted
val res35: List[Int] = List(33, 44, 50, 55, 88, 90)
6.2 指定字段排序
sortBy
方法,可以指定按特定的字段排序,将传入的函数转换后再进行排序。
sortBy
的方法签名为:
def sortBy[R](f: (I) => R): List(R)
例如,定义一个 List
,里面包含了多个元组,元组第一个元素为 球员名称,第二个元素为球员身价,然后再通过身价对元素进行排序:
scala> val players = List(("C朗", 15000000), ("美斯", 21000000), ("姆总", 150000000), ("夏兰特", 180000000))
val players: List[(String, Int)] = List((C朗,15000000), (美斯,21000000), (姆总,150000000), (夏兰特,180000000))
// 按名字排序
scala> players.sortBy(_._1)
val res36: List[(String, Int)] = List((C朗,15000000), (夏兰特,180000000), (姆总,150000000), (美斯,21000000))
// 按身价排序
scala> players.sortBy(_._2)
val res37: List[(String, Int)] = List((C朗,15000000), (美斯,21000000), (姆总,150000000), (夏兰特,180000000))
// 按身价倒序
scala> players.sortBy(0 - _._2)
val res38: List[(String, Int)] = List((夏兰特,180000000), (姆总,150000000), (美斯,21000000), (C朗,15000000))
6.3 自定义排序
使用 sortWith
方法,可以实现自定义排序,该方法的签名如下:
def sortWith(lt: (A, A) => Boolean): List[A]
函数有两个入参,第一个入参为 当前元素
,第二个入参为 上一个元素
。
下面的例子演示了按球员身价做顺序排序 和 倒序排序:
scala> val players = List(("C朗", 15000000), ("美斯", 21000000), ("姆总", 150000000), ("夏兰特", 180000000))
val players: List[(String, Int)] = List((C朗,15000000), (美斯,21000000), (姆总,150000000), (夏兰特,180000000))
// 顺序排序
scala> players.sortWith(_._2 < _._2)
val res48: List[(String, Int)] = List((C朗,15000000), (美斯,21000000), (姆总,150000000), (夏兰特,180000000))
// 倒序排序
scala> players.sortWith(_._2 > _._2)
val res47: List[(String, Int)] = List((夏兰特,180000000), (姆总,150000000), (美斯,21000000), (C朗,15000000))
7 分组
使用 groupBy
方法可以将数据分组后进行统计。
groupBy
的方法签名如下:
def groupBy[K](f: (I) => K): Map(K, List[I])
下面的例子,按国家队球员进行分组:
scala> val players = List("C朗 葡萄牙", "美斯 阿根廷", "B费 葡萄牙", "碧咸 英格兰", "普老师 英格兰")
val players: List[String] = List(C朗 葡萄牙, 美斯 阿根廷, B费 葡萄牙, 碧咸 英格兰, 普老师 英格兰)
scala> players.groupBy(_.split(" ")(1))
val res49: Map[String, List[String]] = HashMap(阿根廷 -> List(美斯 阿根廷), 英格兰 -> List(碧咸 英格兰, 普老师 英格兰), 葡萄牙 -> List(C朗 葡萄牙, B费 葡萄牙))
8 聚合
reduce
提供了聚合功能。聚合就是将一个集合的数据合并为一个,在统计分析中经常使用。
reduce
的方法签名如下:
def reduce[A1 >: A](op: (A1, A1) => A1): A1
[A1 >: A]
中(下界)A1必须是集合类型的子类op: (A1, A1) => A1
用来不断进行聚合操作;第一个A1参数为当前聚合后的变量,第二个 A1 类型参数为当前要进行聚合的元素- 返回值 A1 是列表最终聚合成的值。
下面例子对一个 Int
List
进行求和:
scala> val list = List(1,2,3,4,5,6,7,8,9,10)
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> list.reduce(_+_)
val res51: Int = 55
还有指定了计算方向的聚合方法,reduceLeft
及 reduceRight
例如,对于数列 1,2,3,4,5
,从左往右相减,结果为 1 - 2 - 3 - 4 - 5 = -13
;如果从右往左相减,结果为 5 - 4 - 3 - 2 - 1 = -5
:
scala> List(1,2,3,4,5).reduce(_-_)
val res52: Int = -13
scala> List(1,2,3,4,5).reduceLeft(_-_)
val res53: Int = -13
scala> List(1,2,3,4,5).reduceRight((e1,e2) => e2 - e1)
val res56: Int = -5
注意:
reduce
跟reduceLeft
是一样的,都是从左到右
进行聚合,第一个参数为前值
,第二个参数为当前值
reduceRight
是从右往左
进行聚合,第一个参数为当前值
,第二个参数为前值