Scala 【集合常用方法和函数操作-上】

简介: Scala 【集合常用方法和函数操作-上】

前言

在开发Spark的过程中,最重要的部分就是对集合的操作,这也是在学习Spark中发现对这里知识不足的发现,所以学完Scala好长时间现在又返回来重新学习Scala集合的常用方法和函数操作。这部分学完,基本已经可以熟练使用Scala开发Spark了。

foreach

       foreach 是一种没有返回值的方法,需要传入一个函数来使用,即foreach负责遍历集合,而其中的函数用来对数据进行处理,我们一般会使用匿名函数来当做参数来使用,比较方便。遍历集合(包括字符串也是一种可迭代的集合)。

下面是cmd控制台的使用案例:

scala> arr.foreach(subarr=>{subarr.foreach(println)})
11
22
33
88
99
scala> val str="hello scala"
str: String = hello scala
scala> str.foreach(println)
h
e
l
l
o
s
c
a
l
a

之后使用foreach的场景要比for循环多得多,建议使用foreach取代for循环。


map操作

map操作是针对集合的典型变换操作,它将某个函数应用到集合中的每个元素,并产生一个结果集合;map方法返回一个与原集合类型大小都相同的新集合,只不过元素的类型可能不同。

使用方法

同样传入一个函数作为参数,通常是匿名函数作参数,同样会对集合进行遍历相当于一个升级版的foreach ,但与 foreach 不同的是,map() 是有返回值的

scala> val arr=Array(1,2,3,4,5,6)
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
scala> arr.map((num:Int)=>{num*2})
res7: Array[Int] = Array(2, 4, 6, 8, 10, 12)
scala> val res = arr.map(num=>{num*2})
res: Array[Int] = Array(2, 4, 6, 8, 10, 12)
scala> res
res10: Array[Int] = Array(2, 4, 6, 8, 10, 12)

练习

给出两名学生以及他们的三科成绩(用元组表示),要求求出每名学生的最高成绩(返回一个元组)

scala> val arr = Array(("zs",Array(100,111,120)),("ls",Array(99,58,120)))
arr: Array[(String, Array[Int])] = Array((zs,Array(100, 111, 120)), (ls,Array(99, 58, 120)))
scala> arr.map(people=>{
     | (people._1,people._2.max)})
res1: Array[(String, Int)] = Array((zs,120), (ls,120))

要求2:计算出两名学生优秀的成绩有几个(分数>=90)。

scala> arr.map(student=>(student._1,student._2.map(score=>if(score>=90) 1 else 0).sum))
res3: Array[(String, Int)] = Array((zs,3), (ls,2))

其中 if-else语句有点长,我们可以简写为 score >= 90 ,因为Scala 中的if-else score 语句是默认有返回值的,而 filter 同样要求返回 true 或 false 来判断是否过滤,所以我们这里可以直接简写为 score>=90 ,这就是一个布尔值。


要求3:计算出两名学生的平均值。

scala> arr.map(stu=>(stu._1,stu._2.sum * 1 / stu._2.size))
res6: Array[(String, Int)] = Array((zs,110), (ls,92))

filter

       上面在使用map操作的过程中,我们会发现,map操作虽然可以有返回值,但是它把我们需要的和不需要的都会返回给我们,显然不能满足我们的使用需求,这就需要使用过滤了。

使用方法

       遍历一个集合并从中获取满足条件的元素组成一个新的集合。,返回 true 代表留下,返回false 代表过滤掉。

案例

过滤数组中的奇数,留下偶数。

scala> arr.filter(num=>if(num%2==0) true else false)
res9: Array[Int] = Array(2, 4)

学生成绩大于90分的科目数量:

scala> val arr = Array(("zs",Array(100,111,120)),("ls",Array(99,58,120)))
arr: Array[(String, Array[Int])] = Array((zs,Array(100, 111, 120)), (ls,Array(99, 58, 120)))
scala> arr.map(stu=>(stu._1,stu._2.filter(score=> score>=90).size))
res10: Array[(String, Int)] = Array((zs,3), (ls,2))

flatten

扁平化的意思,适用于对多维数组(集合类型)的压缩合并,注意使用的时候没有括号。

引入

将数组中的所有元素*2:

//一维数组
scala> val arr = Array(1,2,3,4,5,6)
arr: Array[Int] = Array(1, 2, 3, 4, 5, 6)
scala> arr.map(num=> num*2)
res11: Array[Int] = Array(2, 4, 6, 8, 10, 12)                              
//二维数组
scala> val arr1 = Array(arr,arr)
arr1: Array[Array[Int]] = Array(Array(1, 2, 3, 4, 5, 6), Array(1, 2, 3, 4, 5, 6))
scala> arr1.map(arr=> arr.map(num=> num*2))
res12: Array[Array[Int]] = Array(Array(2, 4, 6, 8, 10, 12), Array(2, 4, 6, 8, 10, 12))

       所谓二维数组翻倍,就是先用map遍历第一层数组,内层又是两个数组,对于数组这种集合类型,我们可以继续使用map进行处理,这样就可以对第二层数组中的元素进行处理了。

扁平化

对于刚才的那种二维数组,我们完全可以直接扁平化,将所有元素放到一个集合中去,简化操作。

scala> arr1
res13: Array[Array[Int]] = Array(Array(1, 2, 3, 4, 5, 6), Array(1, 2, 3, 4, 5, 6))
scala> arr1.flatten
res14: Array[Int] = Array(1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6)
scala> arr1.flatten.map(num=>num*2)
res15: Array[Int] = Array(2, 4, 6, 8, 10, 12, 2, 4, 6, 8, 10, 12)

同样,对于集合类型,即使内外层数据类型不一样,只要都是集合类型(除了Map集合,元组也不行)就可以进行压缩!

scala> val arr = Array(List(1,2,3),List(4,5,6))
arr: Array[List[Int]] = Array(List(1, 2, 3), List(4, 5, 6))
scala> arr.flatten
res17: Array[Int] = Array(1, 2, 3, 4, 5, 6)

flatMap

并不是 flatten + map()  而是 map() + flatten

案例

比如我们Spark下的wordcount,假设我们有一个文件,内容为两行:

hello spark
hello scala

Spark 读取进来后,它就变成了:

Array("hello spark","hello sacla")

我们进行 wordcount 的话,就需要先把它先扁平化成一个整体,但是由于这是一个一维的数组,而不是我们扁平化所要求的内层必须也是数组或集合的形式,所以要先把我们每一个字符串元素转换为数组的形式:

Array(Array("hello spark"),Array("hello scala"))

实现过程:

scala> val arr = Array("hello spark","hello sacla")
arr: Array[String] = Array(hello spark, hello sacla)
scala> arr.map(str=> str.split(" "))
res18: Array[Array[String]] = Array(Array(hello, spark), Array(hello, sacla))
scala> res18.flatten
res19: Array[String] = Array(hello, spark, hello, sacla)

元组转为数组

很多时候,我们得到的数据不规范,比如元组类型,这就需要我们将元组转为数组的形式了:

scala> val arr = Array(("1","2"),("3","4"))
arr: Array[(String, String)] = Array((1,2), (3,4))
scala> arr.map(t=>Array(t._1,t._2))
res20: Array[Array[String]] = Array(Array(1, 2), Array(3, 4))

flatMap 用法

flatMap只需要关注 map() 不需要关注 flatten ,因为只要我们的数据满足扁平化操作的要求就可以进行扁平化,更多的我们应该关注的是 map() 的过程中,我们内层元素的格式是否为数组,如果不是(是字符串或者元组),又分别应该怎么做?所以说,我们只需要关注 map 操作即可。

//内层是元组
scala> arr
res24: Array[(String, String)] = Array((1,2), (3,4))
scala> arr.flatMap(t=>Array(t._1,t._2))
res25: Array[String] = Array(1, 2, 3, 4)
//内层是数组
scala> val arr = Array("hello spark","hello scala")
arr: Array[String] = Array(hello spark, hello scala)
scala> arr.flatMap(str=> str.split(" "))
res26: Array[String] = Array(hello, spark, hello, scala)

练习

val arr = Array("zs 90 100 110","ls 50 80 110")
//希望得到
zs 90
zs 100
zs 110
ls 50 
ls 80
ls 110

思路

使用 flatten + 字符串的tail / head

注意:

Array 的 head 属性是单个元素

Array 的 tail 属性是一个元素集合,它代表除了Array中第一个元素外的其他元素,所以可以进行集合操作(map、flatten等)

scala> val arr = Array("zs 90 100 110","ls 50 80 110")
arr: Array[String] = Array(zs 90 100 110, ls 50 80 110)
scala> arr.map(stu=>stu.split(" "))
res27: Array[Array[String]] = Array(Array(zs, 90, 100, 110), Array(ls, 50, 80, 110))
scala> res27.map(arr=>(arr.tail.map(t=>(arr.head,t))))
res28: Array[Array[(String, String)]] = Array(Array((zs,90), (zs,100), (zs,110)), Array((ls,50), (ls,80), (ls,110)))
scala> res28.flatten
res29: Array[(String, String)] = Array((zs,90), (zs,100), (zs,110), (ls,50), (ls,80), (ls,110))

我们可以使用flatMap简化

scala> arr
res30: Array[String] = Array(zs 90 100 110, ls 50 80 110)
scala> arr.map(str=> str.split(" ")).flatMap(arr=> arr.tail.map(t=> (arr.head,t)))
res31: Array[(String, String)] = Array((zs,90), (zs,100), (zs,110), (ls,50), (ls,80), (ls,110))

sorted、sortedBy、sortWith

并行集合

reduce、reduceLeft、reduceRight

fold、foldLeft、foldRight

aggregate

groupBy、grouped

mapValues

diff、union、intersect

实现 wordcount

相关文章
|
27天前
|
Java Scala
Scala 方法与函数
Scala 方法与函数
21 1
|
5月前
|
前端开发 Scala
Scala并发编程的react、loop方法详解
在这个例子中,`MyActor`会无限循环接收和处理消息。当收到一个字符串消息时,它会打印出"Received: "加上消息内容。如果收到其他类型的消息,它会打印"Unknown message"。
30 1
|
6月前
|
前端开发 Scala
Scala并发编程的react、loop方法详解
在这个例子中,`MyActor`会无限循环接收和处理消息。当收到一个字符串消息时,它会打印出"Received: "加上消息内容。如果收到其他类型的消息,它会打印"Unknown message"。
34 0
|
6月前
|
Scala
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
scala-模式匹配(字符串、数组、元组、集合、类、偏函数)
28 0
|
6月前
|
Scala
【收藏】Scala常用方法(笔记)
【收藏】Scala常用方法(笔记)
48 0
|
7月前
|
编译器 Scala
认识scala中的函数
认识scala中的函数
67 5
|
7月前
|
Scala 容器
Scala学习--day04--集合、常用方法、案例实操 - WordCount TopN、不同省份的商品点击排行
Scala学习--day04--集合、常用方法、案例实操 - WordCount TopN、不同省份的商品点击排行
111 2
|
7月前
|
Scala
Scala函数和方法
Scala函数和方法
40 1
|
7月前
|
Scala
Scala综合练习_基于以下List集合实现词频统计
Scala综合练习_基于以下List集合实现词频统计
52 0