avatar

目录
scala中的flatMap和foldLeft函数

scala中的flatMap和foldLeft函数

scala由于其函数式编程的特性,在大数据的处理中被广泛使用。

此文针对scala集合中两个常用的,却不太好理解的函数进行示例讲解。

flatMap

scala中最重要的函数之一,映射扁平化

把握以下三点即可:

1、flatMap = map + flatten

2、什么类型调用的flatMap方法,则返回的也是什么类型

3、先对集合中的每个元素进行map,

再对map后的每个元素(map后的每个元素必须还是集合)中的每个元素进行flatten

[注] 进行map的对象可以是只含一层的集合,但进行flatten操作的对象必需是至少含两层的集合

map和flatten示例:

scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Test0001 {
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
// 集合映射
println("map => " + list.map(x=>{x*2})) //map => List(2, 4, 6, 8)
println("map => " + list.map(x=>x*2)) //map => List(2, 4, 6, 8)
println("map => " + list.map(_*2)) //map => List(2, 4, 6, 8)
// 集合扁平化
val list1 = List(
List(1,2),
List(3,4)
)
println("flatten =>" + list1.flatten) //flatten =>List(1, 2, 3, 4)
}
}

flatMap示例一:

scala
1
2
3
val words = Set("scala", "spark", "hadoop")
val result = words.flatMap(x => x.toUpperCase)
println(result) //Set(A, L, P, C, H, K, R, O, D, S)

flatMap示例二:

scala
1
2
3
4
5
6
val tuples: List[(String, Int)] = List(("Hello Scala", 4), ("Hello Spark", 2))
val strings: List[String] = tuples.map(t=>{(t._1+" ")*t._2})
//List(Hello Scala Hello Scala Hello Scala Hello Scala , Hello Spark Hello Spark )

val flatMapList: List[String] = strings.flatMap(t=>{t.split(" ")})
//List(Hello, Scala, Hello, Scala, Hello, Scala, Hello, Scala, Hello, Spark, Hello, Spark)

flatMap示例三:

scala
1
2
3
4
5
6
7
val linesList = List(("Hello Scala", 4), ("Hello Spark", 2))
val flatMapList: List[(String, Int)] = linesList.flatMap(t => {
val line: String = t._1
val words = line.split(" ")
words.map(w => (w, t._2))
})
println(flatMapList) //List((Hello,4), (Scala,4), (Hello,2), (Spark,2))

根据上述三个原则即可算出函数结果。

foldLeft

集合折叠函数,fold、foldRight底层都是基于foldLeft函数。

所以本文用到的函数可以不用严格区分,主要阐述其原理。

scala
1
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)

就是将集合的数据和集合之外的数据进行聚合操作。

fold方法有函数柯里化,有2个参数列表

  • 第一个参数列表:集合之外的数据

  • 第二个参数列表:表示计算规则

fold示例一:

scala
1
2
3
4
5
val list = List(1, 2, 3, 4)
// 集合折叠
println("fold => " + list.fold(0)(_+_)) //10
// 集合折叠(左)
println("foldLeft => " + list.foldLeft(0)(_+_)) //10

fold示例二:

scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
object Scala21_Collection_Method4 {
def main(args: Array[String]): Unit = {
// 将两个Map集合进行合并(merge)处理
val map1 = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
val map2 = mutable.Map("a" -> 4, "d" -> 5, "c" -> 6)
// Map( "a"->5, "b"->2, "c"->9 ,"d"->5)
val map3 = map2.foldLeft(map1)(
(map, kv) => {
val k = kv._1
val v = kv._2
//map.update(k, map.getOrElse(k, 0) + v)
map(k) = map.getOrElse(k, 0) + v
map
}
)
println(map3) //Map(b -> 2, d -> 5, a -> 5, c -> 9)

println(map1) //Map(b -> 2, d -> 5, a -> 5, c -> 9)
println(map2) //Map(d -> 5, a -> 4, c -> 6)
}
}

原理示意图如下:

folfLeft原理图

总结:

其实,在foldleft函数中,第二个参数规定的就是,

foldleft第一个参数和foldleft调用者的第一个元素的运算规则

可以用如下公式理解:

a. foldLeft( b )( (b,a的第一个元素)=>{} )

(对应上面示意图:红色块为b,蓝色块为a)

只不过在此公式中b和a的第一个元素都是动态变化的:

​ b一直在迭代,a会继续往后顺序取后面的值。

其实函数最终返回值就是b的值(上面的例子map1和map3相等也能证明这一点,本质就是map1把值赋给了map3),且a不发生改变。

文章作者: Yang4
文章链接: https://masteryang4.github.io/2020/04/21/scala%E4%B8%AD%E7%9A%84flatMap%E5%92%8CfoldLeft%E5%87%BD%E6%95%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 MasterYangBlog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论