Scala基本操作

Posted 飞鸟码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala基本操作相关的知识,希望对你有一定的参考价值。

一. 元组

元组可以用来包含一组不同类型的值。例如:姓名,年龄,性别,出生年月。元组的元素是不可变的。




定义元组

语法

使用括号来定义元组

val/var 元组 = (元素1, 元素2, 元素3....)


使用箭头来定义元组(元组只有两个元素)

val/var 元组 = 元素1->元素2



示例

定义一个元组,包含一个学生的以下数据

id 姓名 年龄 地址
1 zhangsan 20 beijing

参考代码

scala> val a = (1, "zhangsan", 20, "beijing")
a: (Int, String, Int, String) = (1,zhangsan,20,beijing)



示例

  • 定义一个元组,包含学生的姓名和年龄(zhangsan、20)

  • 分别使用括号、和箭头来定义元组

参考代码

scala> val a = ("zhangsan", 20)
a: (String, Int) = (zhangsan,20)

scala> val a = "zhangsan" -> 20
a: (String, Int) = (zhangsan,20)




访问元组

使用_1、_2、_3....来访问元组中的元素,_1表示访问第一个元素,依次类推


示例

  • 定义一个元组,包含一个学生的姓名和性别,"zhangsan",  "male"

  • 分别获取该学生的姓名和性别

参考代码

scala> val a = "zhangsan" -> "male"
a: (String, String) = (zhangsan,male)

// 获取第一个元素
scala> a._1
res41: String = zhangsan

// 获取第二个元素
scala> a._2
res42: String = male



二. 列表

列表是scala中最重要的、也是最常用的数据结构。List具备以下性质:

  • 可以保存重复的值

  • 有先后顺序


在scala中,也有两种列表,一种是不可变列表、另一种是可变列表




定义

不可变列表就是列表的元素、长度都是不可变的。


语法

使用List(元素1, 元素2, 元素3, ...)来创建一个不可变列表,语法格式:

val/var 变量名 = List(元素1, 元素2, 元素3...)

使用Nil创建一个不可变的空列表

val/var 变量名 = Nil


使用::方法创建一个不可变列表

val/var 变量名 = 元素1 :: 元素2 :: Nil

[!TIP]

使用::拼接方式来创建列表,必须在最后添加一个Nil



示例一

创建一个不可变列表,存放以下几个元素(1,2,3,4)


参考代码

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



示例二

使用Nil创建一个不可变的空列表


参考代码

scala> val a = Nil
a: scala.collection.immutable.Nil.type = List()



示例三

使用::方法创建列表,包含-2、-1两个元素


参考代码

scala> val a = -2 :: -1 :: Nil
a: List[Int] = List(-2, -1)


可变列表

可变列表就是列表的元素、长度都是可变的。

要使用可变列表,先要导入import scala.collection.mutable.ListBuffer


[!NOTE]

  • 可变集合都在mutable包中

  • 不可变集合都在immutable包中(默认导入)



定义

使用ListBuffer[元素类型]()创建空的可变列表,语法结构:

val/var 变量名 = ListBuffer[Int]()


使用ListBuffer(元素1, 元素2, 元素3...)创建可变列表,语法结构:

val/var 变量名 = ListBuffer(元素1,元素2,元素3...)



示例一

创建空的整型可变列表


参考代码

  scala> val a = ListBuffer[Int]()
 a: scala.collection.mutable.ListBuffer[Int] = ListBuffer()



示例二

创建一个可变列表,包含以下元素:1,2,3,4


参考代码

scala> val a = ListBuffer(1,2,3,4)
a: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4)



可变列表操作

  • 获取元素(使用括号访问(索引值)

  • 添加元素(+=

  • 追加一个列表(++=

  • 更改元素(使用括号获取元素,然后进行赋值

  • 删除元素(-=

  • 转换为List(toList

  • 转换为Array(toArray



示例

  1. 定义一个可变列表包含以下元素:1,2,3

  2. 获取第一个元素

  3. 添加一个新的元素:4

  4. 追加一个列表,该列表包含以下元素:5,6,7

  5. 删除元素7

  6. 将可变列表转换为不可变列表

  7. 将可变列表转换为数组



参考代码

// 导入不可变列表
scala> import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer

// 创建不可变列表
scala> val a = ListBuffer(1,2,3)
a: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)

// 获取第一个元素
scala> a(0)
res19: Int = 1

// 追加一个元素
scala> a += 4
res20: a.type = ListBuffer(1, 2, 3, 4)

// 追加一个列表
scala> a ++= List(5,6,7)
res21: a.type = ListBuffer(1, 2, 3, 4, 5, 6, 7)

// 删除元素
scala> a -= 7
res22: a.type = ListBuffer(1, 2, 3, 4, 5, 6)

// 转换为不可变列表
scala> a.toList
res23: List[Int] = List(1, 2, 3, 4, 5, 6)

// 转换为数组
scala> a.toArray
res24: Array[Int] = Array(1, 2, 3, 4, 5, 6)




列表常用操作

以下是列表常用的操作

  • 判断列表是否为空(isEmpty

  • 拼接两个列表(++

  • 获取列表的首个元素(head)和剩余部分(tail)

  • 反转列表(reverse

  • 获取前缀(take)、获取后缀(drop

  • 扁平化(flaten

  • 拉链(zip)和拉开(unzip

  • 转换字符串(toString

  • 生成字符串(mkString

  • 并集(union

  • 交集(intersect

  • 差集(diff


判断列表是否为空

示例

  • 定义一个列表,包含以下元素:1,2,3,4

  • 使用isEmpty判断列表是否为空

参考代码

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

scala> a.isEmpty
res51: Boolean = false

拼接两个列表

示例

  • 有两个列表,分别包含以下元素1,2,3和4,5,6

  • 使用++将两个列表拼接起来

参考代码

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

scala> val b = List(4,5,6)
b: List[Int] = List(4, 5, 6)

scala> a ++ b
res52: List[Int] = List(1, 2, 3, 4, 5, 6)



获取列表的首个元素和剩余部分

示例

  • 定义一个列表,包含以下几个元素:1,2,3

  • 使用head方法,获取列表的首个元素

  • 使用tail方法,获取除第一个元素以外的元素,它也是一个列表

参考代码

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

scala> a.head
res4: Int = 1

scala> a.tail
res5: List[Int] = List(2, 3)



反转列表

示例

  • 定一个列表,包含以下元素:1,2,3

  • 使用reverse方法将列表的元素反转

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

scala> a.reverse
res6: List[Int] = List(3, 2, 1)



获取列表前缀和后缀

示例

  • 定义一个列表,包含以下元素:1,2,3,4,5

  • 使用take方法获取前缀(前三个元素):1,2, 3

  • 使用drop方法获取后缀(除前三个以外的元素):4,5

参考代码

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

scala> a.take(3)
res56: List[Int] = List(1, 2, 3)

scala> a.drop(3)
res60: List[Int] = List(4, 5)



扁平化(压平)

扁平化表示将列表中的列表中的所有元素放到一个列表中。


示例

  • 有一个列表,列表中又包含三个列表,分别为:List(1,2)、List(3)、List(4,5)

  • 使用flatten将这个列表转换为List(1,2,3,4,5)

参考代码

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

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



拉链与拉开

  • 拉链:使用zip将两个列表,组合成一个元素为元组的列表

  • 拉开:将一个包含元组的列表,解开成包含两个列表的元组


示例

  • 有两个列表

    • 第一个列表保存三个学生的姓名,分别为:zhangsan、lisi、wangwu

    • 第二个列表保存三个学生的年龄,分别为:19, 20, 21

  • 使用zip操作将两个列表的数据"拉"在一起,形成 zhangsan->19, lisi ->20, wangwu->21

参考代码

scala> val a = List("zhangsan", "lisi", "wangwu")
a: List[String] = List(zhangsan, lisi, wangwu)

scala> val b = List(19, 20, 21)
b: List[Int] = List(19, 20, 21)

scala> a.zip(b)
res1: List[(String, Int)] = List((zhangsan,19), (lisi,20), (wangwu,21))



示例

  • 将上述包含学生姓名、年龄的元组列表,解开成两个列表

参考代码

scala> res1.unzip
res2: (List[String], List[Int]) = (List(zhangsan, lisi, wangwu),List(19, 20, 21))



转换字符串

toString方法可以返回List中的所有元素


示例

  • 定义一个列表,包含以下元素:1,2,3,4

  • 使用toString输出该列表的元素

参考代码

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

scala> println(a.toString)
List(1, 2, 3, 4)



生成字符串

mkString方法,可以将元素以分隔符拼接起来。默认没有分隔符


示例

  • 定义一个列表,包含以下元素1,2,3,4

  • 使用mkString,用冒号将元素都拼接起来

参考代码

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

scala> a.mkString
res7: String = 1234

scala> a.mkString(":")
res8: String = 1:2:3:4



并集

union表示对两个列表取并集,不去重


示例

  • 定义第一个列表,包含以下元素:1,2,3,4

  • 定义第二个列表,包含以下元素:3,4,5,6

  • 使用union操作,获取这两个列表的并集

  • 使用distinct操作,去除重复的元素

参考代码

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

scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)

// 并集操作
scala> a1.union(a2)
res17: List[Int] = List(1, 2, 3, 4, 3, 4, 5, 6)

// 可以调用distinct去重
scala> a1.union(a2).distinct
res18: List[Int] = List(1, 2, 3, 4, 5, 6)



交集

intersect表示对两个列表取交集


示例

  • 定义第一个列表,包含以下元素:1,2,3,4

  • 定义第二个列表,包含以下元素:3,4,5,6

  • 使用intersect操作,获取这两个列表的交集

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

scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)

scala> a1.intersect(a2)
res19: List[Int] = List(3, 4)



差集

diff表示对两个列表取差集,例如: a1.diff(a2),表示获取a1在a2中不存在的元素


示例

  • 定义第一个列表,包含以下元素:1,2,3,4

  • 定义第二个列表,包含以下元素:3,4,5,6

  • 使用diff获取这两个列表的差集

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

scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)

scala> a1.diff(a2)
res24: List[Int] = List(1, 2)



三. Set

Set(集)是代表没有重复元素的集合。Set具备以下性质:

  1. 元素不重复

  2. 不保证插入顺序


scala中的集也分为两种,一种是不可变集,另一种是可变集。


不可变集


定义

语法

创建一个空的不可变集,语法格式:

val/var 变量名 = Set[类型]()


给定元素来创建一个不可变集,语法格式:

val/var 变量名 = Set(元素1, 元素2, 元素3...)


示例一

定义一个空的不可变集

参考代码

scala> val a = Set[Int]()
a: scala.collection.immutable.Set[Int] = Set()



示例二

定义一个不可变集,保存以下元素:1,1,3,2,4,8

参考代码

scala> val a = Set(1,1,3,2,4,8)
a: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 8, 4)



基本操作

  • 获取集的大小(size

  • 遍历集(和遍历数组一致

  • 添加一个元素,生成一个Set(+

  • 拼接两个集,生成一个Set(++

  • 拼接集和列表,生成一个Set(++


示例


  1. 创建一个集,包含以下元素:1,1,2,3,4,5

  2. 获取集的大小

  3. 遍历集,打印每个元素

  4. 删除元素1,生成新的集

  5. 拼接另一个集(6, 7, 8)

  6. 拼接一个列表(6,7,8, 9)


参考代码

// 创建集
scala> val a = Set(1,1,2,3,4,5)
a: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)

// 获取集的大小
scala> a.size
res0: Int = 5

// 遍历集
scala> for(i <- a) println(i)

// 删除一个元素
scala> a - 1
res5: scala.collection.immutable.Set[Int] = Set(5, 2, 3, 4)

// 拼接两个集
scala> a ++ Set(6,7,8)
res2: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 8, 4)

// 拼接集和列表
scala> a ++ List(6,7,8,9)
res6: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 9, 2, 7, 3, 8, 4)



可变集


定义

可变集合不可变集的创建方式一致,只不过需要提前导入一个可变集类。

手动导入:import scala.collection.mutable.Set



示例

  1. 定义一个可变集,包含以下元素: 1,2,3, 4

  2. 添加元素5到可变集中

  3. 从可变集中移除元素1


参考代码

scala> val a = Set(1,2,3,4)
a: scala.collection.mutable.Set[Int] = Set(1, 2, 3, 4)                          

// 添加元素
scala> a += 5
res25: a.type = Set(1, 5, 2, 3, 4)

// 删除元素
scala> a -= 1
res26: a.type = Set(5, 2, 3, 4)



四. 映射

Map可以称之为映射。它是由键值对组成的集合。在scala中,Map也分为不可变Map和可变Map。




不可变Map

定义

语法

val/var map = Map(->, ->, ->...) // 推荐,可读性更好
val/var map = Map((, ), (, ), (, ), (, )...)


示例

  1. 定义一个映射,包含以下学生姓名和年龄数据

    "zhangsan", 30
    "lisi", 40
  2. 获取zhangsan的年龄


参考代码

scala> val map = Map("zhangsan"->30, "lisi"->40)
map: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 40)

scala> val map = Map(("zhangsan", 30), ("lisi", 30))
map: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 30)

// 根据key获取value
scala> map("zhangsan")
res10: Int = 30



可变Map

定义

定义语法与不可变Map一致。但定义可变Map需要手动导入import scala.collection.mutable.Map



示例

  1. 定义一个映射,包含以下学生姓名和年龄数据

    "zhangsan", 30
    "lisi", 40
  2. 修改zhangsan的年龄为20


scala> val map = Map("zhangsan"->30, "lisi"->40)
map: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30)

// 修改value
scala> map("zhangsan") = 20


Map基本操作

基本操作

  • 获取值(map(key))

  • 获取所有key(map.keys

  • 获取所有value(map.values

  • 遍历map集合

  • getOrElse

  • 增加key,value对

  • 删除key




示例

  1. 定义一个映射,包含以下学生姓名和年龄数据

    "zhangsan", 30
    "lisi", 40
  2. 获取zhangsan的年龄

  3. 获取所有的学生姓名

  4. 获取所有的学生年龄

  5. 打印所有的学生姓名和年龄

  6. 获取wangwu的年龄,如果wangwu不存在,则返回-1

  7. 新增一个学生:wangwu, 35

  8. 将lisi从可变映射中移除



参考代码

scala> val map = Map("zhangsan"->30, "lisi"->40)
map: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30)

// 获取zhagnsan的年龄
scala> map("zhangsan")
res10: Int = 30

// 获取所有的学生姓名
scala> map.keys
res13: Iterable[String] = Set(lisi, zhangsan)

// 获取所有的学生年龄
scala> map.values
res14: Iterable[Int] = HashMap(40, 30)

// 打印所有的学生姓名和年龄
scala> for((x,y) <- map) println(s"$x $y")
lisi 40
zhangsan 30

// 获取wangwu的年龄,如果wangwu不存在,则返回-1
scala> map.getOrElse("wangwu", -1)
res17: Int = -1

// 新增一个学生:wangwu, 35
scala> map + "wangwu"->35
res22: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30, wangwu -> 35)

// 将lisi从可变映射中移除
scala> map - "lisi"
res23: scala.collection.mutable.Map[String,Int] = Map(zhangsan -> 30)



五. iterator迭代器

scala针对每一类集合都提供了一个迭代器(iterator)用来迭代访问集合




使用迭代器遍历集合

  • 使用iterator方法可以从集合获取一个迭代器

  • 迭代器的两个基本操作

    • hasNext——查询容器中是否有下一个元素

    • next——返回迭代器的下一个元素,如果没有,抛出NoSuchElementException

  • 每一个迭代器都是有状态的

    • 迭代完后保留在最后一个元素的位置

    • 再次使用则抛出NoSuchElementException

  • 可以使用while或者for来逐个返回元素



示例

  1. 定义一个列表,包含以下元素:1,2,3,4,5

  2. 使用while循环和迭代器,遍历打印该列表

参考代码

scala> val ite = a.iterator
ite: Iterator[Int] = non-empty iterator

scala> while(ite.hasNext) {
    | println(ite.next)
    | }



示例

  1. 定义一个列表,包含以下元素:1,2,3,4,5

  2. 使用for 表达式和迭代器,遍历打印该列表

参考代码

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

scala> for(i <- a) println(i)


六. 函数式编程

我们将来使用Spark/Flink的大量业务代码都会使用到函数式编程。下面的这些操作是学习的重点。

  • 遍历(foreach

  • 映射(map

  • 映射扁平化(flatmap

  • 过滤(filter

  • 是否存在(exists

  • 排序(sortedsortBysortWith

  • 分组(groupBy

  • 聚合计算(reduce

  • 折叠(fold




遍历 | foreach

之前,学习过了使用for表达式来遍历集合。我们接下来将学习scala的函数式编程,使用foreach方法来进行遍历、迭代。它可以让代码更加简洁。


方法签名

foreach(f: (A)  Unit): Unit

说明

foreach API 说明
参数 f: (A) ⇒ Unit 接收一个函数对象
函数的输入参数为集合的元素,返回值为空
返回值 Unit


foreach执行过程


示例

有一个列表,包含以下元素1,2,3,4,请使用foreach方法遍历打印每个元素


参考代码

// 定义一个列表
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)

// 迭代打印
scala> a.foreach((x:Int)=>println(x))



使用类型推断简化函数定义

上述案例函数定义有点啰嗦,我们有更简洁的写法。因为使用foreach去迭代列表,而列表中的每个元素类型是确定的

  • scala可以自动来推断出来集合中每个元素参数的类型

  • 创建函数时,可以省略其参数列表的类型


示例

  1. 有一个列表,包含以下元素1,2,3,4,请使用foreach方法遍历打印每个元素

  2. 使用类型推断简化函数定义


参考代码

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

// 省略参数类型
scala> a.foreach(x=>println(x))



使用下划线来简化函数定义

当函数参数,只在函数体中出现一次,而且函数体没有嵌套调用时,可以使用下划线来简化函数定义


示例

  1. 有一个列表,包含以下元素1,2,3,4,请使用foreach方法遍历打印每个元素

  2. 使用下划线简化函数定义


参考代码

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

a.foreach(println(_))


  • 如果方法参数是函数,如果出现了下划线,scala编译器会自动将代码封装到一个函数中

  • 参数列表也是由scala编译器自动处理




七. 映射 | map

集合的映射操作是将来在编写Spark/Flink用得最多的操作,是我们必须要掌握的。因为进行数据计算的时候,就是一个将一种数据类型转换为另外一种数据类型的过程。


map方法接收一个函数,将这个函数应用到每一个元素,返回一个新的列表




用法

方法签名


def map[B](f: (A) B): TraversableOnce[B]

方法解析

map方法 API 说明
泛型 [B] 指定map方法最终返回的集合泛型
参数 f: (A) ⇒ B 传入一个函数对象
该函数接收一个类型A(要转换的列表元素),返回值为类型B
返回值 TraversableOnce[B] B类型的集合


map方法解析


案例一

  1. 创建一个列表,包含元素1,2,3,4

  2. 对List中的每一个元素加1


参考代码

scala> a.map(x=>x+1)
res4: List[Int] = List(2, 3, 4, 5)



案例二

  1. 创建一个列表,包含元素1,2,3,4

  2. 使用下划线来定义函数,对List中的每一个元素加1


参考代码

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

scala> a.map(_ + 1)


扁平化映射 | flatMap

扁平化映射也是将来用得非常多的操作,也是必须要掌握的。



定义

可以把flatMap,理解为先map,然后再flatten


  • map是将列表中的元素转换为一个List

  • flatten再将整个列表进行扁平化



方法签名

def flatMap[B](f: (A)  GenTraversableOnce[B]): TraversableOnce[B]

方法解析

flatmap方法 API 说明
泛型 [B] 最终要转换的集合元素类型
参数 f: (A) ⇒ GenTraversableOnce[B] 传入一个函数对象
函数的参数是集合的元素
函数的返回值是一个集合
返回值 TraversableOnce[B] B类型的集合



案例

案例说明

  1. 有一个包含了若干个文本行的列表:"hadoop hive spark flink flume", "kudu hbase sqoop storm"

  2. 获取到文本行中的每一个单词,并将每一个单词都放到列表中


思路分析

步骤

  1. 使用map将文本行拆分成数组

  2. 再对数组进行扁平化


参考代码

// 定义文本行列表
scala> val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)

// 使用map将文本行转换为单词数组
scala> a.map(x=>x.split(" "))
res5: List[Array[String]] = List(Array(hadoop, hive, spark, flink, flume), Array(kudu, hbase, sqoop, storm))

// 扁平化,将数组中的
scala> a.map(x=>x.split(" ")).flatten
res6: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)



使用flatMap简化操作

参考代码

scala>  val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm)

scala> a.flatMap(_.split(" "))
res7: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)


九. 过滤 | filter

过滤符合一定条件的元素


定义

方法签名

def filter(p: (A)  Boolean): TraversableOnce[A]

方法解析

filter方法 API 说明
参数 p: (A) ⇒ Boolean 传入一个函数对象
接收一个集合类型的参数
返回布尔类型,满足条件返回true, 不满足返回false
返回值 TraversableOnce[A] 列表



案例

  1. 有一个数字列表,元素为:1,2,3,4,5,6,7,8,9

  2. 请过滤出所有的偶数


参考代码


scala> List(1,2,3,4,5,6,7,8,9).filter(_ % 2 == 0)
res8: List[Int] = List(2, 4, 6, 8)



十. 排序

在scala集合中,可以使用以下几种方式来进行排序

  • sorted默认排序

  • sortBy指定字段排序

  • sortWith自定义排序


默认排序 | sorted

示例

  1. 定义一个列表,包含以下元素: 3, 1, 2, 9, 7

  2. 对列表进行升序排序


参考代码

scala> List(3,1,2,9,7).sorted
res16: List[Int] = List(1, 2, 3, 7, 9)



指定字段排序 | sortBy

根据传入的函数转换后,再进行排序

方法签名

def sortBy[B](f: (A)  B): List[A]

方法解析

sortBy方法 API 说明
泛型 [B] 按照什么类型来进行排序
参数 f: (A) ⇒ B 传入函数对象
接收一个集合类型的元素参数
返回B类型的元素进行排序
返回值 List[A] 返回排序后的列表


示例

  1. 有一个列表,分别包含几下文本行:"01 hadoop", "02 flume", "03 hive", "04 spark"

  2. 请按照单词字母进行排序


参考代码

scala> val a = List("01 hadoop", "02 flume", "03 hive", "04 spark")
a: List[String] = List(01 hadoop, 02 flume, 03 hive, 04 spark)

// 获取单词字段
scala> a.sortBy(_.split(" ")(1))
res8: List[String] = List(02 flume, 01 hadoop, 03 hive, 04 spark)



自定义排序 | sortWith

自定义排序,根据一个函数来进行自定义排序


方法签名

def sortWith(lt: (A, A)  Boolean): List[A]

方法解析

sortWith方法 API 说明
参数 lt: (A, A) ⇒ Boolean 传入一个比较大小的函数对象
接收两个集合类型的元素参数
返回两个元素大小,小于返回true,大于返回false
返回值 List[A] 返回排序后的列表



示例

  1. 有一个列表,包含以下元素:2,3,1,6,4,5

  2. 使用sortWith对列表进行降序排序


参考代码

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

scala> a.sortWith((x,y) => if(x<y)true else false)
res15: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> res15.reverse
res18: List[Int] = List(6, 5, 4, 3, 2, 1)



使用下划线简写上述案例


参考代码

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

// 函数参数只在函数中出现一次,可以使用下划线代替
scala> a.sortWith(_ < _).reverse
res19: List[Int] = List(6, 5, 4, 3, 2, 1)



十一. 分组 | groupBy

。我们如果要将数据按照分组来进行统计分析,就需要使用到分组方法




定义

groupBy表示按照函数将列表分成不同的组


方法签名

def groupBy[K](f: (A)  K): Map[K, List[A]]

方法解析

groupBy方法 API 说明
泛型 [K] 分组字段的类型
参数 f: (A) ⇒ K 传入一个函数对象
接收集合元素类型的参数
返回一个K类型的key,这个key会用来进行分组,相同的key放在一组中
返回值 Map[K, List[A]] 返回一个映射,K为分组字段,List为这个分组字段对应的一组数据


groupBy执行过程分析


示例

  1. 有一个列表,包含了学生的姓名和性别:

    "张三", "男"
    "李四", "女"
    "王五", "男"
  2. 请按照性别进行分组,统计不同性别的学生人数


步骤

  1. 定义一个元组列表来保存学生姓名和性别

  2. 按照性别进行分组

  3. 将分组后的Map转换为列表:List(("男" -> 2), ("女" -> 1))


参考代码

scala> val a = List("张三"->"男", "李四"->"女", "王五"->"男")
a: List[(String, String)] = List((张三,), (李四,), (王五,))

// 按照性别分组
scala> a.groupBy(_._2)
res0: scala.collection.immutable.Map[String,List[(String, String)]] = Map( -> List((张三,), (王五,)),
-> List((李四,)))

// 将分组后的映射转换为性别/人数元组列表
scala> res0.map(x => x._1 -> x._2.size)
res3: scala.collection.immutable.Map[String,Int] = Map( -> 2, -> 1)



十二. 聚合操作

聚合操作,可以将一个列表中的数据合并为一个。这种操作经常用来统计分析中




聚合 | reduce

reduce表示将列表,传入一个函数进行聚合计算


定义


方法签名

def reduce[A1 >: A](op: (A1, A1)  A1): A1

方法解析

reduce方法 API 说明
泛型 [A1 >: A] (下界)A1必须是集合元素类型的子类
参数 op: (A1, A1) ⇒ A1 传入函数对象,用来不断进行聚合操作
第一个A1类型参数为:当前聚合后的变量
第二个A1类型参数为:当前要进行聚合的元素
返回值 A1 列表最终聚合为一个元素


reduce执行流程分析


[!NOTE]

  • reduce和reduceLeft效果一致,表示从左到右计算

  • reduceRight表示从右到左计算



案例


  1. 定义一个列表,包含以下元素:1,2,3,4,5,6,7,8,9,10

  2. 使用reduce计算所有元素的和


参考代码

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> a.reduce((x,y) => x + y)
res5: Int = 55

// 第一个下划线表示第一个参数,就是历史的聚合数据结果
// 第二个下划线表示第二个参数,就是当前要聚合的数据元素
scala> a.reduce(_ + _)
res53: Int = 55

// 与reduce一样,从左往右计算
scala> a.reduceLeft(_ + _)
res0: Int = 55

// 从右往左聚合计算
scala> a.reduceRight(_ + _)
res1: Int = 55



折叠 |  fold

fold与reduce很像,但是多了一个指定初始值参数



定义


方法签名

def fold[A1 >: A](z: A1)(op: (A1, A1)  A1): A1

方法解析

reduce方法 API 说明
泛型 [A1 >: A] (下界)A1必须是集合元素类型的子类
参数1 z: A1 初始值
参数2 op: (A1, A1) ⇒ A1 传入函数对象,用来不断进行折叠操作
第一个A1类型参数为:当前折叠后的变量
第二个A1类型参数为:当前要进行折叠的元素
返回值 A1 列表最终折叠为一个元素


[!NOTE]

  • fold和foldLet效果一致,表示从左往右计算

  • foldRight表示从右往左计算



案例


  1. 定义一个列表,包含以下元素:1,2,3,4,5,6,7,8,9,10

  2. 使用fold方法计算所有元素的和


参考代码

scala> val a = List(1,2,3,4,5,6,7,8,9,10)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> a.fold(100)(_ + _)
res4: Int = 155



以上是关于Scala基本操作的主要内容,如果未能解决你的问题,请参考以下文章

为什么Scala是可扩展的?

初学scala4——trait混入

Scala附加列表

scala编程——函数和闭包

详解 Scala 模式匹配

Scala的面向对象与函数编程