Scala学习笔记(黑马视频)

目录

2.Scala第二章节

2.1 输出语句和分号

2.1.1 输出语句

2.1.2 分号

2.2 Scala中的常量

2.2.1 概述

2.2.2 分类

2.2.3 代码演示

2.3. Scala中的变量

2.3.1 概述

2.3.2 语法格式

2.3.3 示例

2.3.4 val和var变量的区别

2.3.5 使用类型推断来定义变量

2.4 字符串

2.4.1 使用双引号

2.4.2 使用插值表达式

2.4.3 使用三引号

2.4.4 扩展: 惰性赋值

2.5 标识符

2.5.1 概述

2.5.2 命名规则

2.5.3 命名规范

2.6 数据类型

2.6.1 简述

2.6.2 数据类型

2.6.3 Scala类型层次结构

2.6.4 思考题

2.7类型转换

2.7.1 概述

2.7.2 自动类型转换

2.7.3 强制类型转换

2.7.4 值类型和String类型之间的相互转换

2. 8 键盘录入

2.8.1 概述

2.8.2 使用步骤

2.8.3 示例

2.9. 案例: 打招呼

2.9.1 概述

2.9.3 参考代码

3.Scala第三章节

3.1 算术运算符

3.1.1 运算符简介

3.1.2 运算符的分类

3.1.3 算术运算符

3.1.4 代码演示

3.2. 赋值运算符

3.2.1 概述

3.2.2 分类

3.2.3 代码演示

3.3. 关系运算符

3.3.1 概述

 3.3.2 分类

3.3.3 代码演示

3.3.4 关系运算符延伸

3.4 逻辑运算符

3.4.1 概述

3.4.2 分类

3.4.3 代码演示

3.5 位运算符

3.5.1 铺垫知识

5.1.1 关于进制

5.1.2 关于8421码

5.1.3 关于整数的原反补码计算规则

3.6 案例: 交换两个变量的值

3.6.1 需求

3.6.2 参考代码

4.Scala第四章节

4.1 流程控制结构

4.1.1 概述

4.1.2 分类

4.2. 顺序结构

4.2.1 概述

4.2.2 代码演示

4.2.3  思考题

4.3选择结构(if语句)

4.3.1 概述

4.3.2 分类

4.3.3 单分支

4.3.4 双分支

4.3.5 多分支

4.3.6 注意事项

4.3.7 嵌套分支

4.3.8 扩展: 块表达式

4.4. 循环结构

4.4.1 概述

4.4.2 分类

4.4.3 for循环

4.4.3 while循环

4.4.5 do…while循环

4.4.6 break和continue

4.5 综合案例

4.5.1 九九乘法表

4.5.2 模拟登陆

10. Scala第十章节

10.1 数组

10.1.1 概述

10.1.2 定长数组

10.1.3 变长数组

10.1.4 遍历数组

10.1.5 数组常用算法

10.2 元组

10.2.1 格式

10.2.2 示例

10.2.3 访问元组中的元素

10.3 列表

10.3.1 不可变列表

10.3.2 可变列表

10.3.3 列表的常用操作

10.4 集

10.4.1 概述

10.4.2 不可变集

10.4.3 可变集

10.5 映射

10.5.1 不可变Map

10.5.2 可变Map

10.5.3 Map基本操作

10. 6. 迭代器(iterator)

10.6.1 概述

10.6.2 注意事项

10.6.3 示例

10.7. 函数式编程

10.7.1遍历(foreach)

10.7.2映射(map)

10.7.3扁平化映射(flatMap)

10.7.4过滤(filter)

10.7.5排序(sorted、sortBy、sortWith)

10.7.6分组(groupBy)

10.7.7聚合操作



2.Scala第二章节

章节目标

  1. 掌握变量, 字符串的定义和使用
  2. 掌握数据类型的划分和数据类型转换的内容
  3. 掌握键盘录入功能
  4. 理解Scala中的常量, 标识符相关内容

2.1 输出语句和分号

2.1.1 输出语句

  1. 方式一:  换行输出

格式:  println(里边写你要打印到控制台的数据);

  1. 方式二: 不换行输出

格式:  print(里边写你要打印到控制台的数据);

注意: 不管是println(), 还是print()语句, 都可以同时打印多个值.格式为: println(值1, 值2, 值3...)

2.1.2 分号

Scala语句中,  单行代码最后的分号可写可不写。 如果是多行代码写在一行, 则中间的分号不能省略, 最后一条代码的分号可省略不写。

**示例**:

println("Hello, Scala!")                  //最后的分号可写可不写

//如果多行代码写在一行, 则前边语句的分号必须写, 最后一条语句的分号可以省略不写.

println("Hello"); println("Scala")  

2.2 Scala中的常量

2.2.1 概述

常量指的是:  在程序的运行过程中, 其值不能发生改变的量。

2.2.2 分类

  1. 字面值常量(常用的有以下几种)

  * 整型常量

  * 浮点型常量

  * 字符常量

  * 字符串常量

  * 布尔常量

  * 空常量

   2.自定义常量(稍后解释)

2.2.3 代码演示

//整型常量

println(10)

//浮点型常量

println(10.3)

//字符常量, 值要用单引号括起来

println('a')

//字符串常量, 值要用双引号括起来

println("abc")

//布尔常量, 值只有true和false

println(true)

//空常量

println(null)

2.3. Scala中的变量

2.3.1 概述

我们将来每一天编写scala程序都会定义变量, 那什么是变量, 它又是如何定义的呢?

变量, 指的就是在程序的执行过程中,  其值可以发生改变的量. 定义格式如下:

2.3.2 语法格式

Java变量定义

int a = 0;

在scala中,可以使用`val`或者`var`来定义变量,语法格式如下:

val/var 变量名:变量类型 = 初始值

其中

- `val`定义的是不可重新赋值的变量, 也就是自定义常量。

- `var`定义的是可重新赋值的变量。

注意: scala中定义变量时, 类型写在变量名后面

2.3.3 示例

需求:定义一个变量保存一个人的名字"Tom"

**步骤**

1. 打开scala解释器

2. 定义一个字符串类型的变量用来保存名字

**参考代码**

scala> val name:String = "tom"

name: String = tom

2.3.4 val和var变量的区别

**示例**

给名字变量进行重新赋值为Jim,观察其运行结果

**参考代码**

scala> name = "Jim"

<console>:12: error: reassignment to val

       name = "Jim"

**示例**

使用`var`重新定义变量来保存名字"Tom",并尝试重新赋值为Jim,观察其运行结果

**参考代码**

scala> var name:String = "tom"

name: String = tom

scala> name = "Jim"

name: String = Jim

注意:  优先使用`val`定义变量,如果变量需要被重新赋值,才使用`var`

2.3.5 使用类型推断来定义变量

scala的语法要比Java简洁,我们可以使用一种更简洁的方式来定义变量。

**示例**

使用更简洁的语法定义一个变量保存一个人的名字"Tom"

**参考代码**

scala> val name = "tom"

name: String = tom

scala可以自动根据变量的值来自动推断变量的类型,这样编写代码更加简洁。

2.4 字符串

scala提供多种定义字符串的方式,将来我们可以根据需要来选择最方便的定义方式。

  1. 使用双引号
  2. 使用插值表达式
  3. 使用三引号

2.4.1 使用双引号

语法

val/var 变量名 = “字符串”

**示例**

有一个人的名字叫"hadoop",请打印他的名字以及名字的长度。

**参考代码**

scala> println(name + name.length)

hadoop6

2.4.2 使用插值表达式

scala中,可以使用插值表达式来定义字符串,有效避免大量字符串的拼接。

语法

val/var 变量名 = s"${变量/表达式}字符串"

注意:

  1. 在定义字符串之前添加`s`
  2. 在字符串中,可以使用`${}`来引用变量或者编写表达式

**示例**

请定义若干个变量,分别保存:"zhangsan"、23、"male",定义一个字符串,保存这些信息。

打印输出:name=zhangsan, age=23, sex=male

**参考代码**

scala> val name = "zhangsan"

name: String = zhangsan

scala> val age = 23

age: Int = 23

scala> val sex = "male"

sex: String = male

scala> val result = s"name=${name}, age=${age}, sex=${sex}"

result: String = name=zhangsan, age=23, sex=male

scala> println(result)

name=zhangsan, age=23, sex=male

2.4.3 使用三引号

如果有大段的文本需要保存,就可以使用三引号来定义字符串。例如:保存一大段的SQL语句。三个引号中间的所有内容都将作为字符串的值。

语法

val/var 变量名 = """字符串1

字符串2"""

**示例**

定义一个字符串,保存以下SQL语句

```sql

select

       *

from

    t_user

where

    name = "zhangsan"

```

打印该SQL语句

**参考代码**

val sql = """select

     | *

     | from

     |     t_user

     | where

     |     name = "zhangsan""""

println(sql)

2.4.4 扩展: 惰性赋值

在企业的大数据开发中,有时候会编写非常复杂的SQL语句,这些SQL语句可能有几百行甚至上千行。这些SQL语句,如果直接加载到JVM中,会有很大的内存开销, 如何解决这个问题呢?

当有一些变量保存的数据较大时,而这些数据又不需要马上加载到JVM内存中。就可以使用**惰性赋值**来提高效率。

语法格式:

lazy val/var 变量名 = 表达式

**示例**

在程序中需要执行一条以下复杂的SQL语句,我们希望只有用到这个SQL语句才加载它。

"""insert overwrite table adm.itcast_adm_personas

    select

    a.user_id,

    a.user_name,

    a.user_sex,

    a.user_birthday,

    a.user_age,

    a.constellation,

    a.province,

    a.city,

    a.city_level,

    a.hex_mail,

    a.op_mail,

    a.hex_phone,

    a.fore_phone,

    a.figure_model,

    a.stature_model,

    b.first_order_time,

    b.last_order_time,

      ...

    d.month1_hour025_cnt,

    d.month1_hour627_cnt,

    d.month1_hour829_cnt,

    d.month1_hour10212_cnt,

    d.month1_hour13214_cnt,

    d.month1_hour15217_cnt,

    d.month1_hour18219_cnt,

    d.month1_hour20221_cnt,

    d.month1_hour22223_cnt

    from gdm.itcast_gdm_user_basic a

      left join gdm.itcast_gdm_user_consume_order b on a.user_id=b.user_id

    left join gdm.itcast_gdm_user_buy_category c on a.user_id=c.user_id

    left join gdm.itcast_gdm_user_visit d on a.user_id=d.user_id;"""

**参考代码**

scala> lazy val sql = """insert overwrite table adm.itcast_adm_personas

     |     select

     |     a.user_id,

       ....

     |     left join gdm.itcast_gdm_user_buy_category c on a.user_id=c.user_id

     |     left join gdm.itcast_gdm_user_visit d on a.user_id=d.user_id;"""

sql: String = <lazy>

2.5 标识符

2.5.1 概述

​       实际开发中, 我们会编写大量的代码, 这些代码中肯定会有变量, 方法, 类等。 那它们该如何命名呢? 这就需要用到标识符了。 标识符就是用来给变量, 方法, 类等起名字的。 Scala中的标识符和Java中的标识符非常相似。

2.5.2 命名规则

  1. 必须由`大小写英文字母, 数字, 下划线_, 美元符$`, 这四部分任意组合组成.
  2. 数字不能开头.
  3. 不能和Scala中的关键字重名.
  4. 最好做到见名知意。

2.5.3 命名规范

  1. 变量或方法: 从第二个单词开始, 每个单词的首字母都大写, 其他字母全部小写(小驼峰命名法).

  zhangSanAge, student_Country, getSum

  1. 类或特质(Trait): 每个单词的首字母都大写, 其他所有字母全部小写(大驼峰命名法)

  Person, StudentDemo, OrderItems

  1. 包: 全部小写, 一般是公司的域名反写, 多级包之间用.隔开

  com.itheima.add,  cn.itcast.update

2.6 数据类型

2.6.1 简述

数据类型是用来约束变量(常量)的取值范围的. Scala也是一门强类型语言, 它里边的数据类型绝大多数和Java一样。我们主要来学习

  1. 与Java不一样的一些用法
  2. scala中数据类型的继承体系

2.6.2 数据类型

基础类型

类型说明

Byte

8位带符号整数

Short

16位带符号整数

Int

32位带符号整数

Long

64位带符号整数

Char

16位无符号Unicode字符

String

Char类型的序列(字符串)

Float

32位单精度浮点数

Double

64位双精度浮点数

Boolean

true或false

注意下 scala类型与Java的区别

  1. scala中所有的类型都使用**大写字母**开头
  2. 整形使用`Int`而不是Integer
  3. scala中定义变量可以不写类型,让scala编译器自动推断
  4. Scala中默认的整型是Int, 默认的浮点型是: Double

2.6.3 Scala类型层次结构

类型

说明

Any

所有类型的父类,它有两个子类AnyRef与AnyVal

AnyVal

所有数值类型的父类

AnyRef

所有对象类型(引用类型)的父类

Unit

表示空,Unit是AnyVal的子类,它只有一个的实例

Null

Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是

Nothing

所有类型的子类

2.6.4 思考题

以下代码是否有问题?

val b:Int = null

Scala会解释报错Null类型并不能转换为Int类型,说明Null类型并不是Int类型的子类

2.7类型转换

2.7.1 概述

当Scala程序在进行运算或者赋值动作时,  范围小的数据类型值会自动转换为范围大的数据类型值, 然后再进行计算。例如: 1 + 1.1的运算结果就是一个Double类型的2.1。 而有些时候, 我们会涉及到一些类似于"四舍五入"的动作, 要把一个小数转换成整数再来计算。这些内容就是Scala中的类型转换。

Scala中的类型转换分为`值类型的类型转换`和`引用类型的类型转换`, 这里我们先重点介绍:`值类型的类型转换`。

  1. 值类型的类型转换分为:
  • 自动类型转换
  • 强制类型转换

2.7.2 自动类型转换

  1. 解释

   范围小的数据类型值会自动转换为范围大的数据类型值, 这个动作就叫: 自动类型转换.

   `自动类型转换从小到大分别为:Byte, Short, Char -> Int -> Long -> Float -> Double `

  1. 示例代码

   val a:Int = 3

   val b:Double = 3 + 2.21     //因为是int类型和double类型的值进行计算, 所以最终结果为: Double类型

   val c:Byte = a + 1 //这样写会报错, 因为最终计算结果是Int类型的数据, 将其赋值Byte类型肯定不行。

2.7.3 强制类型转换

  1. 解释

   范围大的数据类型值通过一定的格式(强制转换函数)可以将其转换成范围小的数据类型值, 这个动作就叫: 强制类型转换.

   注意: 使用强制类型转换的时候可能会造成精度缺失问题!

  1. 格式

val/var 变量名:数据类型 = 具体的值.toXxx  //Xxx表示你要转换到的数据类型

  1. 参考代码

val a:Double = 5.21

val b:Int = a.toInt

2.7.4 值类型和String类型之间的相互转换

  1. 值类型的数据转换成String类型

格式一:

val/var 变量名:String = 值类型数据 + ""

格式二:

val/var 变量名:String = 值类型数据.toString

**示例**

将Int, Double, Boolean类型的数据转换成其对应的字符串形式.

**参考代码**:

val a1:Int = 10

val b1:Double = 2.1

val c1:Boolean = true

//方式一: 通过和空字符串拼接的形式实现

val a2:String = a1 + ""

val b2:String = b1 + ""

val c2:String = c1 + ""

//方式二: 通过toString函数实现

val a3:String = a1.toString

val b3:String = b1.toString

val c3:String = c1.toString

  1. String类型的数据转换成其对应的值类型

格式:

val/var 变量名:值类型 = 字符串值.toXxx      //Xxx表示你要转换到的数据类型

注意

  1. String类型的数据转成Char类型的数据, 方式有点特殊, 并不是调用toChar, 而是toCharArray
  2. 这点目前先了解即可, 后续我们详细解释

**需求:**

​       将字符串类型的整数, 浮点数, 布尔数据转成其对应的值类型数据.

**参考代码:**

val s1:String = "100"

val s2:String = "2.3"

val s3:String = "false"

//将字符串类型的数据转成其对应的: Int类型

val a:Int = s1.toInt

//将字符串类型的数据转成其对应的: Double类型

val b:Double = s2.toDouble

//将字符串类型的数据转成其对应的: Boolean类型

val c:Boolean = s3.toBoolean

2. 8 键盘录入

2.8.1 概述

前边我们涉及到的数据, 都是我们写"死"的, 固定的数据, 这样做用户体验并不是特别好.  那如果这些数据是由用户录入, 然后我们通过代码接收, 就非常好玩儿了. 这就是接下来我们要学习的Scala中的"键盘录入"功能.

2.8.2 使用步骤

  1. 导包

格式: import scala.io.StdIn

  1. 通过`StdIn.readXxx()`来接收用户键盘录入的数据

  • 接收字符串数据:  StdIn.readLine()
  • 接收整数数据:  StdIn.readInt()

2.8.3 示例

  • 提示用户录入字符串, 并接收打印.

  println("请录入一个字符串: ")

  val str = StdIn.readLine()

  println("您录入的字符串内容为: " + str)

  • 提示用户录入整数, 并接收打印.

  println("请录入一个整数: ")

  val num = StdIn.readInt()

  println("您录入的数字为: " + num)

2.9. 案例: 打招呼

2.9.1 概述

聊了这么久, 赶紧来和小伙伴儿们来打个招呼吧.

需求:  提示用户录入他/她的姓名和年龄, 接收并打印.

2.9.2 具体步骤

  1. 提示用户录入姓名.
  2. 接收用户录入的姓名.
  3. 提示用户录入年龄.
  4. 接收用户录入的年龄.
  5. 将用户录入的数据(姓名和年龄)打印到控制台上.

2.9.3 参考代码

//1. 提示用户录入姓名.

println("请录入您的姓名: ")

//2. 接收用户录入的姓名.

val name = StdIn.readLine()

//3. 提示用户录入年龄.

println("请录入您的年龄: ")

//4. 接收用户录入的年龄.

val age = StdIn.readInt()

//5. 将用户录入的数据(姓名和年龄)打印到控制台上.

println(s"大家好, 我叫${name}, 我今年${age}岁了, 很高兴和大家一起学习Scala!")

3.Scala第三章节

章节目标

  1. 理解运算符的相关概述
  2. 掌握算术, 赋值, 关系, 逻辑运算符的用法
  3. 掌握交换变量案例
  4. 理解位运算符的用法

3.1 算术运算符

3.1.1 运算符简介

用来拼接变量或者常量的符号就叫: 运算符, 而通过运算符连接起来的式子就叫: 表达式。 实际开发中, 我们会经常用到它.

例如:

​       10 + 3 这个就是一个表达式, 而+号, 就是一个运算符.

注意: 在Scala中, 运算符并不仅仅是运算符, 也是函数的一种, 这点大家先了解即可, 后续我们详细讲解.

3.1.2 运算符的分类

  • 算术运算符

  • 赋值运算符

  • 关系运算符

  • 逻辑运算符

  • 位运算符

注意: Scala中是没有三元运算符的, 被if-else给替代了。

 同一优先级的运算符,运算次序由结合方向所决定。
简单记就是:! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

3.1.3 算术运算符

算术运算符指的是用来进行算术操作的符号,  常用的有以下几种:

运算符

功能解释

+

加号,功能有3点.

1)表示正数

2)普通的加法操作

3)字符串的拼接

-

减号,功能有2点.

1)表示负数

2)普通的减法操作

*

乘号,用于获取两个数据的乘积

/

除法,用于获取两个数据的商

%

取余(也叫取模),用于获取两个数据的余数

注意:

  1). Scala中是没有++, --这两个算术运算符的, 这点和Java中不同.

2). 整数相除的结果, 还是整数. 如果想获取到小数, 则必须有浮点型数据参与.

例如: 10 / 3  结果是3      10 / 3.0  结果是: 3.3333(无限循环)`

 3). 关于+号拼接字符串: 任意类型的数据和字符串拼接, 结果都将是一个新的字符串.

 4). 关于%操作, 假设求`a % b`的值, 它的底层原理其实是:  `a - a/b * b`

3.1.4 代码演示

需求: 演示算术运算符的常见操作.

参考代码:

//演示+号操作

println(+3)

println(10 + 3)

println("hello" + 10)

//演示-号操作

println(-5)

println(10 - 5)

//演示*号操作

println(5 * 3)

//演示/号操作

println(10 / 3)

println(10 / 3.0)

//演示%(取余)操作

println(10 % 3)     //结果是1, 具体运算过程: 10 - 10/3 * 3   = 10 - 3 * 3   = 1

println(10 % -3)    //结果是1, 具体运算过程: 10 - 10/-3 * -3 = 10 - -3 * -3 = 10 - 9  =  1

println(-10 % 3)   //结果是-1, 具体运算过程: -10 - -10/3 * 3 = -10 - -3 * 3 = -10 + 9 = -1

3.2. 赋值运算符

3.2.1 概述

赋值运算符指的是用来进行赋值操作的符号。 例如: 把一个常量值, 或者一个变量值甚至是某一段代码的执行结果赋值给变量, 这些都要用到赋值运算符。

3.2.2 分类

赋值运算符常用的有两类

  1. 基本赋值运算符

`=`就是基本的赋值运算符,  例如:  var a:Int = 3,  就是把常量值3赋值给变量a

  1. 扩展赋值运算符

    `+=, -=, *=, /=, %=`

   注意:

  1). 赋值运算符的左边必须是: 变量, 不能是常量。    例如:  3 = 5,   这种写法就是错误的.

   2). 关于扩展赋值运算符, 其实就是把左边的数据和右边的数据进行指定的操作, 然后把结果赋值给左边.

   例如; a += 3 就是把变量a的值和常量3进行加法操作, 然后把结果赋值给变量a

3.2.3 代码演示

//将常量值1赋值给变量a

var a:Int = 1               //注意: 因为后续代码要修改变量a的值, 所以变量a要用var修饰

//对变量a进行加3操作, 然后把结果重新赋值给变量a

a += 3                  //a的最终结果为: a = 4

//对变量a进行减2操作, 然后把结果重新赋值给变量a

a -= 2                   //a的最终结果为: a = 2

//对变量a进行乘3操作, 然后把结果重新赋值给变量a

a *= 3                  //a的最终结果为: a = 6

//对变量a进行除2操作, 然后把结果重新赋值给变量a

a /= 2                   //a的最终结果为: a = 3

//对变量a和2进行取余操作, 然后把结果重新赋值给变量a

a %= 2                 //a的最终结果为: a = 1

3.3. 关系运算符

3.3.1 概述

关系运算符指的是用来进行比较操作的符号。例如: 数据是否相等, 是否不等, 数据1大还是数据2大...等这些操作.

运算符

功能解释

>

用来判断前边的数据`是否大于`后边的数据

>=

用来判断前边的数据`是否大于或者等于`后边的数据

<

用来判断前边的数据`是否小于`后边的数据

<=

用来判断前边的数据`是否小于或者等于`后边的数据

==

用来判断两个数据`是否相等`

!=

用来判断两个数据`是否不等`

 3.3.2 分类

注意:

  1). 关系表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.

2). 千万不要把==写成=, 否则结果可能不是你想要的.

3.3.3 代码演示

//定义两个Int类型的变量a, b, 分别赋值为3, 5

var a:Int = 3

var b:Int = 5

//判断a是否大于b, 并打印结果      

println(a > b)                                   //false

//判断a是否大于等于b, 并打印结果

println(a >= 3)                                //true

//判断a是否小于b, 并打印结果

println(a < b)                                   //true

//判断a是否小于等于b, 并打印结果

println(a <= 3)                                //true

//判断a和b是否不等, 并打印结果

println(a != b)                                 //true

//判断a和b是否相等, 并打印结果

println(a == b)                                //false

//如果把==写成了=, 其实是把变量b的值赋值给变量a

println(a = b)                                   //输出结果是一对小括号"()", 即: 没有打印值.

println(a)                                         //再次打印变量a, 打印结果是:5

3.3.4 关系运算符延伸

学过Java的同学会发现, 上述的Scala中的关系运算符用法和Java中是一样的,  那有和Java不一样的地方吗?

答案是: 有.

| 需求描述           | Scala代码  | Java代码     |

| 比较数据值         | == 或者 != | equals()方法 |

| 比较引用值(地址值) | eq方法     | == 或者 !=   |

**示例**

有一个字符串"abc",再创建第二个字符串,值为:在第一个字符串后拼接一个空字符串。

然后使用比较这两个字符串是否相等、再查看它们的引用值是否相等。

**参考代码**

val s1 = "abc"

val s2 = s1 + ""

s1 == s2     //结果是: true,  因为比较的是 数据值

s1.eq(s2)       //结果是: false, 因为比较的是 地址值

3.4 逻辑运算符

3.4.1 概述

逻辑运算符指的是`用来进行逻辑操作的符号`。 可以简单理解为它是: 组合判断. 例如: 判断多个条件是否都满足, 或者满足其中的某一个, 甚至还可以对某个判断结果进行取反操作。

3.4.2 分类

运算符

功能解释

&&

逻辑与,要求所有条件都满足(即:结果为true),

简单记忆:有false则整体为false.

||

逻辑或,要求只要满足任意一个条件即可,简单记忆:有true则整体为true.

!

逻辑非,用来进行取反操作的.

注意:

1). 逻辑表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.

2). 在Scala代码中, 不能对一个Boolean类型的数据进行**连续取反**操作,  但是在Java中是可以的.

* 即:   !!false,  这样写会报错, 不支持这种写法.

3.4.3 代码演示

//相当于: false && true

println(3 > 5 && 2 < 3)           //结果为: false

//我们可以简写代码为:

//逻辑与: 有false则整体为false.

println(false && true)              //结果为: false

println(true && false)              //结果为: false

println(false && false)            //结果为: false

println(true && true)        //结果为: true

println(false || true)           //结果为: true

println(true || false)           //结果为: true

println(false || false)          //结果为: false

println(true || true)             //结果为: true

println(!false)                           //结果为: true

println(!true)                     //结果为: false

println(!!true)                           //这样写会报错, Scala不支持这种写法, 但是Java代码支持这种写法.

3.5 位运算符

3.5.1 铺垫知识

要想学好`位运算符`, 你必须得知道三个知识点:

1. 什么是进制

2. 什么是8421码

3. 整数的原码, 反码, 补码计算规则

5.1.1 关于进制

通俗的讲, 逢几进一就是几进制, 例如: 逢二进一就是二进制, 逢十进一就是十进制, 常用的进制有以下几种:

| 进制名称 | 数据组成规则                                                 | 示例                   |

| -------- | ------------------------------------------------------------ | ---------------------- |

| 二进制   | 数据以0b(大小写均可)开头, 由数字0和1组成                     | 0b10001001, 0b00101010 |

| 八进制   | 数据以0开头, 由数字0~7组成                                   | 064,  011              |

| 十进制   | 数据直接写即可,  无特殊开头, 由数字0~9组成                   | 10, 20, 333            |

| 十六进制 | 数据以0x(大小写均可)开头,  由数字0~9, 字母A-F组成(大小写均可) | 0x123F, 0x66ABC        |

注意:关于二进制的数据,  最前边的那一位叫: 符号位, 0表示正数, 1表示负数.  其他位叫: 数值位.

例如: 0b10001001 结果就是一个: 负数,   0b00101010 结果就是一个:  正数.

5.1.2 关于8421码

8421码就是用来描述`二进制位和十进制数据之间的关系的`, 它可以帮助我们快速的计算数据的二进制或十进制形式.

8421码对应关系如下:

​       **二进制位**                         0     0     0     0     0     0     0     0           

​       **对应的十进制数据**         128 64   32   16   8     4     2     1

> 注意:

>

>  1. 计算规则:  二进制位从右往左数, 每多一位, 对应的十进制数据 乘以2.

>  2. 二进制和十进制相互转换的小技巧:

>

>      *  二进制转十进制:  获取该二进制位对应的十进制数据, 然后累加即可.

>        * 例如: 0b101对应的十进制数据计算步骤:  4 + 0 + 1 = 5

>      * 十进制转二进制:  对十进制数据进行拆解, 看哪些数字相加等于它, 然后标记成二进制即可.

>        * 例如: 10 对应的二进制数据计算步骤: 10 = 8 + 2  =   0b1010

5.1.3 关于整数的原反补码计算规则

所谓的原反补码, 其实指的都是二进制数据, 把十进制的数据转成其对应的二进制数据, 该二进制数据即为: 原码.

> 注意: 计算机底层存储, 操作和运算数据, 都是采用`数据的二进制补码形式`来实现的.

* 正数

  * 正数的原码, 反码, 补码都一样, 不需要特殊计算.

* 负数

  * 负数的反码计算规则:  原码的符号位不变, 数值位按位取反(以前为0现在为1, 以前为1现在为0)

  * 负数的补码计算规则:  反码 + 1

#### 5.2 概述

位运算符指的就是`按照位(Bit)来快速操作数据值`, 它只针对于整型数据.  因为计算机底层存储, 操作, 运算采用的都是数据的二进制补码形式, 且以后我们要经常和海量的数据打交道, 为了提高计算效率, 我们就可以使用位运算符来实现快速修改数据值的操作.

#### 5.3 分类

| 运算符 | 功能解释                                                     |

| ------ | ------------------------------------------------------------ |

| &      | 按位与,  规则: 有0则0,  都为1则为1.                          |

| \|     | 按位或,  规则: 有1则1,  都为0则为0.                          |

| ^      | 按位异或, 规则: 相同为0, 不同为1.                            |

| ~      | 按位取反, 规则: 0变1, 1变0.                                  |

| <<     | 按位左移, 规则: 每左移一位, 相当于该数据乘2, 例如:  2 << 1, 结果为4 |

| \>>    | 按位右移, 规则: 每右移一位, 相当于该数据除2, 例如:  6 >> 1, 结果为3 |

> 注意:

>

> 1. 位运算符只针对于整型数据.

> 2. 运算符操作的是数据的二进制补码形式.

> 3. 小技巧: 一个数字被同一个数字位异或两次, 该数字值不变. 即: 10 ^ 20 ^ 20, 结果还是10

#### 5.4 代码演示

```scala

//定义两个变量a和b, 初始化值分别为: 3, 5

val a = 3              //二进制数据: 0000 0011

val b = 5                     //二进制数据: 0000 0101

//结果为: 0000 0001, 转化成十进制, 结果为: 1

println(a & b)             //打印结果为: 1

//结果为: 0000 0111, 转化成十进制, 结果为: 7

println(a | b)        //打印结果为: 7

//结果为: 0000 0110, 转换成十进制, 结果为: 6

println(a ^ b)              //打印结果为: 6

//计算流程: 1111 1100(补码) -> 1111 1011(反码) -> 1000 0100(原码) -> 十进制数据: -4

println(~ a)          //打印结果为: -4

//计算流程: 1000 0011(-3原码) -> 1111 1100(-3反码) -> 1111 1101(-3补码) -> 0000 0010(取反后新补码) -> 十进制数据: 2

println(~ -3)        //打印结果为: 2

//计算流程: 0000 0011(3的补码) -> 0000 1100(新的补码) -> 十进制数据: 12

println(a << 2)           //打印结果为: 12

//计算流程: 0000 0011(3的补码) -> 0000 0001(新的补码) -> 十进制数据: 1

println(a >> 1)           //打印结果为: 1

println(a ^ b ^ b) //打印结果为: 3

3.6 案例: 交换两个变量的值

3.6.1 需求

已知有两个Int类型的变量a和b, 初始化值分别为10和20, 请写代码实现变量a和变量b的值的交换.

即最终结果为: a=20, b=10. 

注意: 不允许直接写`a=20, b=10`这种代码.

3.6.2 参考代码

* **方式一:  通过算术运算符实现.**

  //定义两个Int类型的变量a和b, 初始化值分别为10和20

  var a = 10

  var b = 20

  //将变量a和b的计算结果赋值给变量a

  a = a + b   //a = 30, b = 20

  //计算并赋值

  b = a - b    //a = 30, b = 10

  a = a - b    //a = 20, b = 10

  //打印结果

  println("a: " + a)           //a: 20

  println("b: " + b)           //b: 10

* **方式二: 通过定义临时变量实现**

  //定义两个Int类型的变量a和b, 初始化值分别为10和20

  var a = 10

  var b = 20

  //定义临时变量temp, 记录变量a的值

  var temp = a                  //a = 10, b = 20, temp = 10

  //把变量b的值赋值给a

  a = b                              //a = 20, b = 20, temp = 10

  //把临时变量temp的值赋值给b

  b = temp                        //a = 20, b = 10, temp = 10

  //打印结果

  println("a: " + a)           //a: 20

  println("b: " + b)           //b: 10

* **方式三: 通过位运算符实现**

  //定义两个Int类型的变量a和b, 初始化值分别为10和20

  var a = 10

  var b = 20

  //定义临时变量temp, 记录变量a和b的位异或值(这个值不需要我们计算)

  var temp = a ^ b     //即: temp = 10 ^ 20

  //通过位异或进行交换变量值 

  a = a ^ temp           //运算流程: a = a ^ temp = a ^ a ^ b = 10 ^ 10 ^ 20 = 20

  b = b ^ temp           //运算流程: b = b ^ temp = b ^ a ^ b = 20 ^ 10 ^ 20 = 10

  //打印结果

  println("a: " + a)    //a: 20

  println("b: " + b)    //b: 10

4.Scala第四章节

章节目标

  1. 掌握分支结构的格式和用法
  2. 掌握for循环和while循环的格式和用法
  3. 掌握控制跳转语句的用法
  4. 掌握循环案例
  5. 理解do…while循环的格式和用法

4.1 流程控制结构

4.1.1 概述

在实际开发中, 我们要编写成千上万行代码, 代码的顺序不同, 执行结果肯定也会受到一些影响, 并且有些代码是满足特定条件才能执行的, 有些代码是要重复执行的. 那如何合理规划这些代码呢? 这就需要用到: 流程控制结构了.

4.1.2 分类

  1. 顺序结构

  1. 选择(分支)结构

  1. 循环结构

  注意: Scala和Java中的流程控制结构是基本一致的.

4.2. 顺序结构

4.2.1 概述

顺序结构是指: 程序是按照从上至下, 从左至右的顺序, 依次逐行执行的, 中间没有任何判断和跳转。

注意: 顺序结构是Scala代码的默认流程控制结构.

4.2.2 代码演示

val a = 10

println("a: " + a) //打印结果为10

println("键盘敲烂, ")

println("月薪过万! ")

4.2.3  思考题

下边这行代码的打印结果应该是什么呢?

println(10 + 10 + "Hello,Scala" + 10 + 10)

 提示: 代码是按照从上至下, 从左至右的顺序, 依次逐行执行的.

4.3选择结构(if语句)

4.3.1 概述

选择结构是指: 某些代码的执行需要依赖于特定的判断条件, 如果判断条件成立, 则代码执行, 否则, 代码不执行.

4.3.2 分类

  • 单分支
  • 双分支
  • 多分支

4.3.3 单分支

所谓的单分支是指: 只有一个判断条件的if语句.

  1. 格式

if(关系表达式) {

    //具体的代码

}

注意: 关系表达式不管简单还是复杂, 结果必须是Boolean类型的值.

   2. 执行流程

                a)先执行关系表达式, 看其结果是true还是false.

                b)如果是true, 则执行具体的代码, 否则, 不执行.

                c)如图:

     d)示例

**需求: **

​       定义一个变量记录某个学生的成绩, 如果成绩大于或者等于60分, 则打印: 分数及格.

**参考代码**

//定义变量, 记录成绩

val score = 61

//判断成绩是否不小于60分

if(score >= 60) {

    println("成绩及格")

}

4.3.4 双分支

所谓的双分支是指: 只有两个判断条件的if语句.

  1. 格式

if(关系表达式) {

    //代码1

} else {

    //代码2

}

  1. 执行流程

    1. 先执行关系表达式, 看其结果是true还是false.
    2. 如果是true, 则执行代码1. 如果是false, 则执行代码2.
    3. 如图:

  1. 示例

**需求: **

​       定义一个变量记录某个学生的成绩, 如果成绩大于或者等于60分, 则打印: 分数及格, 否则打印分数不及格.

**参考代码**

//定义变量, 记录成绩

val score = 61

//判断成绩是否不小于60分

if(score >= 60) {

    println("成绩及格")

} else {

    println("成绩不及格")

}

4.3.5 多分支

所谓的多分支是指: 有多个判断条件的if语句.

  1. 格式

if(关系表达式1) {

    //代码1

} else if(关系表达式2) {

    //代码2

}else if(关系表达式n) {  //else if可以有多组

    //代码n

} else {

    //代码n+1                  //所有的关系表达式都不成立的时候, 执行这里的代码.

}

  1. 执行流程

    1. 先执行关系表达式1, 看其结果是true还是false.
    2. 如果是true, 则执行代码1,  分支语句结束. 如果是false, 则执行关系表达式2, 看其结果是true还是false.
    3. 如果是true, 则执行代码2.  分支语句结束. 如果是false, 则执行关系表达式3, 看其结果是true还是false.
    4. 以此类推, 直到所有的关系表达式都不满足, 执行最后一个else中的代码.
    5. 如图:

  1. 示例

**需求: **

​       定义一个变量记录某个学生的成绩, 根据成绩发放对应的奖励, 奖励机制如下:

​       [90, 100]             ->          VR设备一套

​       [80, 90)        ->          考试卷一套

​       [0, 80)          ->          组合拳一套

​       其他             ->          成绩无效

**参考代码**

//定义变量, 记录成绩

val score = 80

//根据成绩发放对应的奖励

if(score >= 90 && score <= 100) {

    println("VR设备一套")

} else if(score >= 80 && score < 90) {

    println("考试卷一套")

} else if(score >= 0 && score < 80) {

    println("组合拳一套")

} else {

    println("成绩无效")

}

4.3.6 注意事项

if语句在使用时, 要注意的事项有以下三点:

  1. 和Java一样, 在Scala中, 如果大括号{}内的逻辑代码只有一行, 则大括号可以省略.
  2. 在scala中,条件表达式也是有返回值的
  3. 在scala中,没有三元表达式,可以使用if表达式替代三元表达式

**示例**

定义一个变量sex,再定义一个result变量,如果sex等于"male",result等于1,否则result等于0

**参考代码**

//定义变量, 表示性别

val sex = "male"

//定义变量, 记录if语句的返回值结果

val result = if(sex == "male") 1 else 0

//打印结果为 result: 1

println("result: " + result)

4.3.7 嵌套分支

有些时候, 我们会涉及到"组合判断", 即一个分支结构中又嵌套了另一个分支结构, 这种写法就叫嵌套分支. 里边的那个分支结构叫: 内层分支, 外边的那个分支结构叫: 外层分支.

**示例**

定义三个变量a,b,c, 初始化值分别为: 10, 20, 30, 通过if分支语句, 获取其中的最大值.

**思路分析**

  1. 定义三个变量a, b, c, 分别记录要进行操作的值.
  2. 定义变量max, 用来记录获取到的最大值.
  3. 先判断a是否大于或者等于b.
  4. 条件成立, 说明 a大(或者等于b), 接着比较a和c的值, 获取最大值, 并将结果赋值给变量max
  5. 条件不成立, 说明 b大, 接着比较b和c的值, 获取最大值, 并将结果赋值给变量max
  6. 此时, max记录的就是a, b, c这三个变量的最大值, 打印即可。

**参考代码**

//1. 定义三个变量a, b, c, 分别记录要进行操作的值.

val a = 10

val b = 20

val c = 30

//2. 定义变量max, 用来记录获取到的最大值.

var max = 0

//3. 先判断a是否大于或者等于b.

if(a >= b) {

    //4. 走这里说明a大(或者等于b), 接着比较a和c的值

    max = if(a >= c) a else c

} else {

    //5.  走这里说明b大, 接着比较b和c的值

    max = if(b >= c) b else c

}

//6. 打印max的值

println("max: " + max)

注意: 嵌套一般不超过3层.

4.3.8 扩展: 块表达式

      1. scala中,使用{}表示一个块表达式
      2. 和if表达式一样,块表达式也是有值的
      3. 值就是最后一个表达式的值

**问题**

请问以下代码,变量a的值是什么?

val a = {

   println("1 + 1")

   1 + 1

}

println("a: " + a)

4.4. 循环结构

4.4.1 概述

循环,指的是事物周而复始的变化。而Scala中的循环结构,是指: 使一部分代码按照次数或一定的条件反复执行的一种代码结构。例如: 打印10次"Hello, Scala!", 如果纯写输出语句, 需要写10次, 而通过循环来实现的话, 输出语句只需要写1次, 这样就变得很简单了.

4.4.2 分类

  • for循环
  • while循环
  • do.while循环

注意: 这三种循环推荐使用for循环, 因为它的语法更简洁, 更优雅.

4.4.3 for循环

在Scala中, for的格式和用法和Java中有些差异, Scala中的for表达式功能更加强大.

  1. 格式

for(i <- 表达式/数组/集合) {

    //逻辑代码

}

 注意: 执行流程和Java一致

  1. 简单循环

**需求: **

​       打印10次"Hello, Scala!"

**参考代码: **

//定义一个变量, 记录1到10的数字

val nums = 1 to 10     //to是Scala中的一个关键字

//通过for循环, 打印指定的内容

for(i <- nums) {

     println("Hello, Scala! " + i)

}

**上述代码可以简写成: **

for(i <- 1 to 10) println("Hello, Scala! " + i)

  1. 嵌套循环

**需求: **使用for表达式,打印以下字符, 每次只能输出一个"*"

```scala

*****

*****

*****

**步骤**

  • 使用for表达式打印3行,5列星星
  • 每打印5个星星,换行

**参考代码**

//写法一: 普通写法

    for (i <- 1 to 3) { //外循环控制行数

      for (j <- 1 to 5) { //内循环控制列数

        print("*") //每次打印一个*

      }

      println() //打印完一行(5个*)之后, 记得换行

    }

    //写法二: 压缩版

    for (i <- 1 to 3) {

      //这是两行代码

      for (j <- 1 to 5)

        if (j == 5)

          println("*")

        else

          print("*")

    }

    //写法三: 合并版

    for (i <- 1 to 3; j <- 1 to 5)

      if (j == 5)

        println("*")

      else

  1. 守卫

for表达式中,可以添加if判断语句,这个if判断就称之为守卫。我们可以使用守卫让for表达式更简洁。    

**语法**

for(i <- 表达式/数组/集合 if 表达式) {

    //逻辑代码

}

**示例**

使用for表达式打印1-10之间能够整除3的数字

**参考代码**

// 添加守卫,打印能够整除3的数字

for(i <- 1 to 10 if i % 3 == 0) println(i)

  1. for推导式

Scala中的for循环也是有返回值的, 在for循环体中,可以使用yield表达式构建出一个集合(可以简单理解为: 就是一组数据),我们把使用yield的for表达式称之为**推导式.**

**示例**

生成一个10、20、30...100的集合

**参考代码**

// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合

val v = for(i <- 1 to 10) yield i * 10

println(v)

4.4.3 while循环

scala中while循环和Java中是一致的, 所以学起来非常简单.

  1. 格式

初始化条件

while(判断条件) {

    //循环体

    //控制条件

}

  1. 执行流程

    1. 执行初始化条件
    2. 执行判断条件, 看其结果是true还是false
    3. 如果是false则循环结束
    4. 如果是true则执行循环体
    5. 执行控制条件
    6. 返回第二步, 重复执行

  1. 示例

**需求: **

​       打印1-10的数字

**参考代码**

//初始化条件

var i = 1

//判断条件

while(i <= 10) {

    //循环体

    println(i)

    //控制条件

    i = i + 1

}

4.4.5 do…while循环

scala中do…while循环和Java中是一致的, 所以学起来非常简单.

  1. 格式

初始化条件

do{

    //循环体

    //控制条件

}while(判断条件)

  1. 执行流程

    1. 执行初始化条件
    2. 执行循环体
    3. 执行控制条件
    4. 执行判断条件, 看其结果是true还是false
    5. 如果是false则循环结束
    6. 如果是true则返回第2步继续执行

注意

  • do.while循环不管判断条件是否成立, 循环体都会执行一
  • for循环, while循环都是如果判断条件不成立, 则循环体不执行

  1. 示例

**需求: **

​       打印1-10的数字

**参考代码**

//初始化条件

var i = 1

do{

    //循环体

    println(i)

    //控制条件

    i = i + 1

}while(i <= 10)   //判断条件

4.4.6 break和continue

在scala中,类似Java和C++的break/continue关键字被移除了

如果一定要使用break/continue,就需要使用scala.util.control包下的Breaks类的**breakble**和**break**方法。

  1. 实现break

**用法**

1). 导包.

  import scala.util.control.Breaks._

2). 使用breakable将for表达式包起来

3). for表达式中需要退出循环的地方,添加`break()`方法调用

**示例**

使用for表达式打印1-10的数字,如果遇到数字5,则退出for表达式

**参考代码**

// 导入scala.util.control包下的Break

import scala.util.control.Breaks._

breakable{

    for(i <- 1 to 10) {

        if(i == 5) break() else println(i)

    }

}

  1. 实现continue

**用法**

continue的实现与break类似,但有一点不同:

注意:

 1). 实现break是用breakable{}将整个for表达式包起来.

 2). 而实现continue是用breakable{}将for表达式的循环体包含起来就可以了.

**示例**

用for表达式打印1~10之间, 所有不能整除3的数字.

// 导入scala.util.control包下的Break   

import scala.util.control.Breaks._

for(i <- 1 to 100 ) {

    breakable{

        if(i % 3 == 0) break()

        else println(i)

    }

}

4.5 综合案例

4.5.1 九九乘法表

**需求: **

打印九九乘法表,  如下图:

**步骤**

1). 通过外循环控制打印的行数.

2). 通过内循环控制每行打印的列数.

 注意:  因为列数是随着行数递增的, 即:

行数

该行的总列数

1

1

2

2

3

3

n

n

     

结论: 如果用**i**表示行数, 那么该行的列数取值范围为: [1, i]

**参考代码**

* **方式一: 普通写法**

//外循环控制行

for(i <- 1 to 9) {        

    //内循环控制列

    for(j <- 1 to i) {

        print(s"${i} * ${j} = ${i * j}\t")

    }

    println()                     //别忘了换行

}

* **方式二: 合并版写法**

//外循环控制行

for(i <- 1 to 9; j <- 1 to i) {            

    print(s"${i} * ${j} = ${i * j}\t")

    if(j == i) println()      //别忘了换行

}

4.5.2 模拟登陆

**需求: **

老王要登陆黑马官网学习Scala,  假设老王的账号和密码分别为"itcast", "heima", 且同一账号只有3次登陆机会, 如果3次都录入错误, 则提示账号被锁定. 请用所学模拟该场景。

**步骤**

1). 导包

    scala.io.StdIn

    scala.util.control.Breaks._

2).  定义变量, 记录用户录入的账号和密码。

3). 因为涉及到break的动作, 所以要用breakable{}把整个for表达式包裹起来

4). 因为只有3次登陆机会, 所以推荐使用for循环。

5). 提示用户录入他/她的账号和密码, 并接收。

6). 判断用户录入的账号和密码是否正确。

7). 如果录入正确, 则提示"登陆成功, 开始学习Scala!", 循环结束.

8). 如果录入错误, 则判断是否还有登陆机会

    有, 则提示"用户名或者密码错误, 您还有*次机会", 然后返回第5步继续执行。

    没有, 则提示"账号被锁定, 请与管理员联系", 循环结束。

**参考代码**

//1). 导包

import scala.io.StdIn

import scala.util.control.Breaks._

//2). 定义变量, 记录用户录入的账号和密码

var username = ""

var password = ""

//3). 因为涉及到break的动作, 所以要用breakable{}把整个for表达式包裹起来

breakable {

      //4). 因为只有3次登陆机会, 所以推荐使用for循环.

    for(i <- 1 to 3) {

        //5). 提示用户录入他/她的账号和密码, 并接收.

        println("请录入您的账号: ")

        username = StdIn.readLine()

        println("请录入您的密码: ")

        password = StdIn.readLine()

        //6). 判断用户录入的账号和密码是否正确.

        if(username == "itcast" && password == "heima") {

            //7. 走到这里, 说明登陆成功, 循环结束.

            println("登陆成功, 开始学习Scala吧!")

            break()

        } else {

            //8. 走到这里, 说明登陆失败. 则判断是否还有登陆机会

            if(i == 3) println("账号被锁定, 请与管理员联系!")

            else println(s"用户名或者密码错误, 您还有${3 - i}次机会")

        }

    } 

}

10. Scala第十章节

章节目标

1. 掌握数组, 元组相关知识点

2. 掌握列表, 集, 映射相关知识点

3. 了解迭代器的用法

4. 掌握函数式编程相关知识点

5. 掌握学生成绩单案例

10.1 数组

10.1.1 概述

数组就是用来存储多个同类型元素的容器, 每个元素都有编号(也叫: 下标, 脚标, 索引), 且编号都是从 0 开始数的。

 Scala中, 有两种数组,一种是定长数组,另一种是变长数组。

10.1.2 定长数组

(1)特点

1). 数组的长度不允许改变.

2). 数组的内容是可变的.

(2)语法

  • 格式一:通过指定长度定义数组

  val/var 变量名 = new Array[元素类型](数组长度)

  • 格式二:通过指定元素定义数组

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

 注意:

  1).  在scala中,数组的泛型使用[]来指定.

2).  使用数组名(索引)来获取数组中的元素.

  3).  数组元素是有默认值的, Int:0, Double:0.0, String: null

  4).  通过数组名.length或者数组名.size来获取数组的长度.

(3)示例

需求

1). 定义一个长度为 10 的整型数组, 设置第 1 个元素为11, 并打印第 1 个元素.

2). 定义一个包含"java", "scala", "python"这三个元素的数组, 并打印数组长度.

参考代码

//案例: 演示定长数组

object ClassDemo01 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个长度为 10 的整型数组, 设置第 1 个元素为 11 , 并打印第 1 个元素.

    val arr1 = new Array[Int](10)

    arr1(0) = 11

    println(arr1(0)) //打印数组的第 1 个元素.

    println("-" * 15) //分割线

    // 2. 定义一个包含"java", "scala", "python"这三个元素的数组, 并打印数组长度.

    val arr2 = Array("java", "scala", "python")

    println(arr2.length) //打印数组的长度

  }

}

10.1.3 变长数组

(1)特点

数组的**长度和内容都是可变的,可以往数组中添加、删除元素.

(2)语法

创建变长数组,需要先导入ArrayBuffer类.

import scala.collection.mutable.ArrayBuffer

  • 定义格式一: 创建空的ArrayBuffer变长数组

val/var 变量名 = ArrayBuffer[元素类型]()

  • 定义格式二: 创建带有初始元素的ArrayBuffer变长数组

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

(3)示例一: 定义变长数组

1.  定义一个长度为 0 的整型变长数组.

2.  定义一个包含"hadoop", "storm", "spark"这三个元素的变长数组.

3.  打印结果.

参考代码

// 1. 导包.

import scala.collection.mutable.ArrayBuffer

//案例: 演示变长数组

object ClassDemo02 {

  def main(args: Array[String]): Unit = {

    // 2. 定义一个长度为 0 的整型变长数组.

    val arr1 = ArrayBuffer[Int]()

    println(s"arr 1 : $arr1")

    // 3. 定义一个包含"hadoop", "storm", "spark"这三个元素的变长数组.

    val arr2 = ArrayBuffer("hadoop", "storm", "spark")

    println(s"arr 2 : $arr2")

  }

}

(4)示例二: 增删改元素

针对Scala中的变长数组, 可通过下述方式来修改数组中的内容.

格式

+ 使用`+=`添加单个元素

+ 使用`-=`删除单个元素

+ 使用`++=`追加一个数组到变长数组中

+ 使用`--=`移除变长数组中的指定多个元素

示例

1. 定义一个变长数组,包含以下元素: "hadoop", "spark", "flink"

2. 往该变长数组中添加一个"flume"元素

3. 从该变长数组中删除"hadoop"元素

4. 将一个包含"hive", "sqoop"元素的数组, 追加到变长数组中.

5. 从该变长数组中删除"sqoop", "spark"这两个元素.

6. 打印数组, 查看结果.

参考代码

//导包

import scala.collection.mutable.ArrayBuffer

//案例: 修改变长数组中的内容.

object ClassDemo03 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个变长数组,包含以下元素: "hadoop", "spark", "flink"

    val arr = ArrayBuffer("hadoop", "spark", "flink")

    // 2. 往该变长数组中添加一个"flume"元素

    arr += "flume"

    // 3. 从该变长数组中删除"hadoop"元素

    arr -= "hadoop"

    // 4. 将一个包含"hive", "sqoop"元素的数组, 追加到变长数组中.

    arr ++= Array("hive", "sqoop")

    // 5. 从该变长数组中删除"sqoop", "spark"这两个元素.

    arr --= Array("sqoop", "spark")

    // 6. 打印数组, 查看结果.

    println(s"arr: $arr")

  }

}

10.1.4 遍历数组

(1)概述

 在Scala中, 可以使用以下两种方式来遍历数组:

1).  使用索引遍历数组中的元素

2).  使用for表达式直接遍历数组中的元素

(2)示例

1. 定义一个数组,包含以下元素1,2,3,4,

2. 通过两种遍历方式遍历数组,并打印数组中的元素

参考代码

//案例: 遍历数组

object ClassDemo04 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个数组,包含以下元素 1 , 2 , 3 , 4 , 5

    val arr = Array(1, 2, 3, 4, 5)

    // 2. 通过两种遍历方式遍历数组,并打印数组中的元素.

    //方式一: 遍历索引的形式实现.

    for (i <- 0 to arr.length - 1) println(arr(i))

    println("-" * 15) //分割线

    for (i <- 0 until arr.length) println(arr(i))

    //方式二: 直接遍历数组元素.

    println("-" * 15) //分割线

    for (i <- arr) println(i)

    //其他方式

    println("-" * 15) //分割线

    for (i <- arr.indices) println(arr(i))

  }

}

注意

  0 until n 获取0~n之间的所有整数, 包含0, 不包含n.

  0 to n 获取0~n之间的所有整数, 包含0, 也包含n.

10.1.5 数组常用算法

(1)概述

 Scala中的数组封装了一些常用的计算操作,将来在对数据处理的时候,不需要我们自己再重新实现, 而是可以直接拿来用。以下为常用的几个算法:

-sum()方法: 求和

- max()方法: 求最大值

- min()方法: 求最小值

- sorted()方法: 排序, 返回一个新的数组.

- reverse()方法: 反转, 返回一个新的数组.

(2)需求

1. 定义一个数组, 包含4, 1, 6, 5, 2, 3这些元素.

2. 在main方法中, 测试上述的常用算法.

参考代码

//案例: 数组的常用算法

object ClassDemo05 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个数组, 包含 4 , 1 , 6 , 5 , 2 , 3 这些元素.

    val arr = Array(4, 1, 6, 5, 2, 3)

    // 2. 在main方法中, 测试上述的常用算法.

    //测试sum

    println(s"sum: ${arr.sum}")

    //测试max

    println(s"max: ${arr.max}")

    //测试min

    println(s"min: ${arr.min}")

    //测试sorted

    val arr2 = arr.sorted //即: arr 2 的内容为: 1 , 2 , 3 , 4 , 5 , 6

    //测试reverse

    val arr3 = arr.sorted.reverse //即: arr 3 的内容为: 6 , 5 , 4 , 3 , 2 , 1

    // 3. 打印数组.

    for (i <- arr) print(s"$i ")

    println("\n" + "-" * 15)

    for (i <- arr2) print(s"$i ")

    println("\n" + "-" * 15)

    for (i <- arr3) print(s"$i ")

  }

}

10.2 元组

   元组一般用来存储多个不同类型的值。例如同时存储姓名,年龄,性别,出生年月这些数据, 就要用到元组来存储了。并且元组的长度和元素都是不可变的。

10.2.1 格式

格式一: 通过小括号实现

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

格式二: 通过箭头来实现

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

注意: 上述这种方式, 只适用于元组中只有两个元素的情况.

10.2.2 示例

需求

1. 定义一个元组,包含学生的姓名和年龄.

2. 分别使用小括号以及箭头的方式来定义元组.

参考代码

//案例: 演示元组的定义格式

object ClassDemo06 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个元组,包含学生的姓名和年龄.

    // 2. 分别使用小括号以及箭头的方式来定义元组.

    val tuple1 = ("张三", 23)

    val tuple2 = "张三" -> 23

    println(tuple1)

    println(tuple2)

  }

}

10.2.3 访问元组中的元素

在Scala中, 可以通过元组名._编号的形式来访问元组中的元素,_1表示访问第一个元素,依次类推.

也可以通过元组名.productIterator的方式, 来获取该元组的迭代器, 从而实现遍历元组.

(1)格式

- 格式一: 访问元组中的单个元组

  println(元组名._ 1 ) //打印元组的第一个元素.

  println(元组名._ 2 ) //打印元组的第二个元组.

- 格式二: 遍历元组

  val tuple1 = (值 1 , 值 2 , 值 3 , 值 4 , 值 5 ...) //可以有多个值

  val it = tuple1.productIterator //获取当前元组的迭代器对象

  for(i <- it) println(i) //打印元组中的所有内容.

(2)示例

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

2. 分别获取该学生的姓名和性别, 并将结果打印到控制台上.

(3)参考代码

//案例: 获取元组中的元组.

object ClassDemo07 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个元组,包含一个学生的姓名和性别,"张三", "male"

    val tuple1 = "张三" -> "male"

    // 2. 分别获取该学生的姓名和性别

    //方式一: 通过 _编号 的形式实现.

    println(s"姓名: ${tuple1._1}, 性别: ${tuple1._2}")

    //方式二: 通过迭代器遍历的方式实现.

    //获取元组对应的迭代器对象.

    val it = tuple1.productIterator

    //遍历元组.

    for (i <- it) println(i)

  }

}

10.3 列表

列表(List)是Scala中最重要的, 也是最常用的一种数据结构。它存储的数据, 特点是:有序, 可重复。

在Scala中,列表分为两种, 即:不可变列表和可变列表。

(1)解释

1. 有序的意思并不是排序, 而是指元素的存入顺序和取出顺序是一致的.

2. 可重复的意思是列表中可以添加重复元素

10.3.1 不可变列表

(1)特点

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

(2)语法

格式一: 通过小括号直接初始化.

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

格式二: 通过Nil创建一个空列表.

  val/var 变量名 = Nil

格式三: 使用::方法实现.

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

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

(3)示例

需求

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

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

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

参考代码

//案例: 演示不可变列表.

object ClassDemo08 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4)

    // 2. 使用`Nil`创建一个不可变的空列表

    val list2 = Nil

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

    val list3 = -2 :: -1 :: Nil

    // 4. 打印结果.

    println(s"list 1 : $list1")

    println(s"list 2 : $list2")

    println(s"list 3 : $list3")

  }

}

10.3.2 可变列表

(1)特点

可变列表指的是列表的元素、长度都是可变的.

(2)语法

要使用可变列表, 必须先导包.

import scala.collection.mutable.ListBuffer

小技巧: 可变集合都在mutable包中, 不可变集合都在immutable包中(默认导入).

 格式一: 创建空的可变列表.

  val/var 变量名 = ListBuffer[数据类型]()

 格式二: 通过小括号直接初始化.

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

(3)

需求

1. 创建空的整形可变列表.

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

参考代码

//案例: 演示可变列表.

// 1. 导包

import scala.collection.mutable.ListBuffer

object ClassDemo09 {

  def main(args: Array[String]): Unit = {

    // 2. 创建空的整形可变列表.

    val list1 = new ListBuffer[Int]()

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

    val list2 = ListBuffer(1, 2, 3, 4)

    println(s"list 1 : $list1")

    println(s"list 2 : $list2")

  }

}

(4)可变列表的常用操作

关于可变列表的常见操作如下:

格式

功能

列表名(索引)

根据索引(索引从0开始),获取列表中的指定元素.

列表名(索引)= 值

修改元素值

+=

往列表中添加单个元素

++=

往列表中追加一个列表

-=

删除列表中的某个指定元素

--=

以列表的形式,删除列表中的多个元素.

toList

将可变列表(ListBuffer)转换为不可变列表(List)

toArray

将可变列表(ListBuffer)转换为数组

             

示例

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

2. 获取第一个元素, 并打印结果到控制台.

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

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

5. 删除元素 7

6. 删除元素3, 4

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

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

9. 打印结果.

参考代码

//案例: 演示可变列表的常见操作.

import scala.collection.mutable.ListBuffer

object ClassDemo10 {

  def main(args: Array[String]): Unit = {

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

    val list1 = ListBuffer(1, 2, 3)

    // 2. 获取第一个元素, 并打印结果到控制台.

    println(list1(0))

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

    list1 += 4

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

    list1 ++= List(5, 6, 7)

    // 5. 删除元素 7

    list1 -= 7

    // 6. 删除元素 3 , 4

    list1 --= List(3, 4)

    // 7. 将可变列表转换为不可变列表

    val list2 = list1.toList

    // 8. 将可变列表转换为数组

    val arr = list1.toArray

    // 9. 打印结果.

    println(s"list 1 : $list1")

    println(s"list 2 : $list2")

    println(s"arr: $arr")

  }

}

10.3.3 列表的常用操作

(1)格式详解

在实际开发中, 我们经常要操作列表, 以下列举的是列表的常用的操作:

格式

功能

isEmpty

判断列表是否为空

++

拼接两个列表,返回一个新的列表

head

获取列表的首个元素

tail

获取列表中除首个元素之外,其他所有的元素

reverse

对列表进行反转,返回一个新的列表

take

获取列表中的前缀元素(具体个数可以自定义)

drop

获取列表中的后缀元素(具体个数可以自定义)

flatten

对列表进行扁平化操作,返回一个新的列表

zip

对列表进行拉链操作,即:将两个列表合并成一个列表

unzip

对列表进行拉开操作,即:将一个列表拆解成两个列表

toString

将列表转换成其对应的默认字符串形式

mkString

将列表转换成其对应的指定字符串形式

union

获取两个列表的并集元素,并返回一个新的列表

intersect

获取两个列表的交集元素,并返回一个新的列表

diff

获取两个列表的差集元素,并返回一个新的列表

#### 3.3.2 示例一: 基础操作

##### 需求

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

2. 使用isEmpty方法判断列表是否为空, 并打印结果.

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

4. 使用++将两个列表拼接起来, 并打印结果.

5. 使用head方法,获取列表的首个元素, 并打印结果.

6. 使用tail方法,获取列表中除首个元素之外, 其他所有的元素, 并打印结果.

7. 使用reverse方法将列表的元素反转, 并打印反转后的结果.

8. 使用take方法获取列表的前缀元素, 并打印结果.

9. 使用drop方法获取列表的后缀元素, 并打印结果.

##### 参考代码

```scala

//案例: 演示列表的基础操作.

object ClassDemo11 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4)

    // 2. 使用isEmpty方法判断列表是否为空, 并打印结果.

    println(s"isEmpty: ${list1.isEmpty}")

    // 3. 再定义一个列表list 2 ,包含以下元素: 4 , 5 , 6

    val list2 = List(4, 5, 6)

    // 4. 使用`++`将两个列表拼接起来, 并打印结果.

    val list3 = list1 ++ list2

    println(s"list 3 : $list3")

    // 5. 使用head方法,获取列表的首个元素, 并打印结果.

    println(s"head: ${list3.head}")

    // 6. 使用tail方法,获取列表中除首个元素之外, 其他所有的元素, 并打印结果.

    println(s"tail: ${list3.tail}")

    // 7. 使用reverse方法将列表的元素反转, 并打印反转后的结果.

    val list4 = list3.reverse

    println(s"list 4 : $list4")

    // 8. 使用take方法获取列表的前缀元素(前三个元素), 并打印结果.

    println(s"take: ${list3.take(3)}")

    // 9. 使用drop方法获取列表的后缀元素(除前三个以外的元素), 并打印结果.

    println(s"drop: ${list3.drop(3)}")

  }

}

```

#### 3.3.3 示例二: 扁平化(压平)

##### 概述

 扁平化表示将嵌套列表中的所有具体元素单独的放到一个新列表中. 如下图:

> 注意: 如果某个列表中的所有元素都是列表, 那么这样的列表就称之为: 嵌套列表.

![扁平化](C:\Users\han\Desktop\大数据\笔记\5、scala\3、\pictures\扁平化.png)

##### 需求

1. 定义一个列表, 该列表有三个元素, 分别为:List(1,2)、List(3)、List(4,5)

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

3. 打印结果.

##### 参考代码

```scala

//案例: 演示扁平化操作.

object ClassDemo12 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个列表, 该列表有三个元素, 分别为:List( 1 , 2 )、List( 3 )、List( 4 , 5 )

    val list1 = List(List(1, 2), List(3), List(4, 5))

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

    val list2 = list1.flatten

    // 3. 打印结果

    println(list2)

  }

}

```

#### 3.3.4 示例三: 拉链与拉开

##### 概述

- 拉链:将两个列表,组合成一个元素为元组的列表

> 解释: 将列表List("张三", "李四"), List(23, 24)组合成列表List((张三,23), (李四,24))

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

> 解释: 将列表List((张三,23), (李四,24))拆解成元组(List(张三, 李四),List(23, 24))

##### 需求

1. 定义列表names, 保存三个学生的姓名,分别为:张三、李四、王五

2. 定义列表ages, 保存三个学生的年龄,分别为:23, 24, 25

3. 使用zip将列表names和ages, 组合成一个元素为元组的列表list

4. 使用unzip将列表list1拆解成包含两个列表的元组tuple

5. 打印结果

##### 参考代码

```scala

//案例: 演示拉链与拉开

object ClassDemo13 {

  def main(args: Array[String]): Unit = {

    // 1. 定义列表names, 保存三个学生的姓名,分别为:张三、李四、王五

    val names = List("张三", "李四", "王五")

    // 2. 定义列表ages, 保存三个学生的年龄,分别为: 23 , 24 , 25

    val ages = List(23, 24, 25)

    // 3. 使用zip将列表names和ages, 组合成一个元素为元组的列表list1.

    val list1 = names.zip(ages)

    // 4. 使用unzip将列表list 1 拆解成包含两个列表的元组tuple1

    val tuple1 = list1.unzip

    // 5. 打印结果

    println("拉链: " + list1)

    println("拉开: " + tuple1)

  }

}

```

#### 3.3.5 示例四: 列表转字符串

##### 概述

将列表转换成其对应的字符串形式, 可以通过toString方法或者mkString方法实现, 其中

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

- `mkString`方法: 可以将元素以指定分隔符拼接起来。

> 注意: 默认没有分隔符.

##### 需求

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

2. 使用toString方法输出该列表的元素

3. 使用mkString方法, 用冒号将元素都拼接起来, 并打印结果.

##### 参考代码

```scala

//案例: 演示将列表转成其对应的字符串形式.

object ClassDemo14 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4)

    // 2. 使用toString方法输出该列表的元素

    println(list1.toString)

    //简写形式, 因为: 输出语句打印对象, 默认调用了该对象的toString()方法

    println(list1)

    println("-" * 15)

    // 3. 使用mkString方法, 用冒号将元素都拼接起来, 并打印结果.

    println(list1.mkString(" : "))

  }

}

```

#### 3.3.6 示例五: 并集, 交集, 差集

##### 概述

操作数据时, 我们可能会遇到求并集, 交集, 差集的需求, 这是时候就要用到union, intersect, diff这些方法了, 其中

- `union`: 表示对两个列表取并集,而且不去重

> 例如: list1.union(list2), 表示获取list1和list2中所有的元素(元素不去重).

>

> 如果想要去除重复元素, 则可以通过distinct实现.

>

- `intersect`: 表示对两个列表取交集

> 例如: list1.intersect(list2), 表示获取list1, list2中都有的元素.

>

- `diff`: 表示对两个列表取差集.

> 例如:list1.diff(list2),表示获取list1中有, 但是list2中没有的元素.

>

##### 需求

1. 定义列表list1,包含以下元素:1,2,3,

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

3. 使用union获取这两个列表的并集

4. 在第三步的基础上, 使用distinct去除重复的元素

5. 使用intersect获取列表list1和list2的交集

6. 使用diff获取列表list1和list2的差集

7. 打印结果

##### 参考代码

```scala

//案例: 演示获取并集, 交集, 差集.

object ClassDemo15 {

  def main(args: Array[String]): Unit = {

    // 1. 定义列表list 1 ,包含以下元素: 1 , 2 , 3 , 4

    val list1 = List(1, 2, 3, 4)

    // 2. 定义列表list 2 ,包含以下元素: 3 , 4 , 5 , 6

    val list2 = List(3, 4, 5, 6)

    // 3. 使用union获取这两个列表的并集

    val unionList = list1.union(list2)

    // 4. 在第三步的基础上, 使用distinct去除重复的元素

    val distinctList = unionList distinct

    // 5. 使用intersect获取列表list 1 和list 2 的交集

    val intersectList = list1.intersect(list2)

    // 6. 使用diff获取列表list 1 和list 2 的差集

    val diffList = list1.diff(list2)

    // 7. 打印结果

    println("并集, 不去重: " + unionList)

    println("并集, 去重: " + distinctList)

    println("交集: " + intersectList)

    println("差集: " + diffList)

  }

}

```

10.4 集

10.4.1 概述

Set(也叫: 集)代表没有重复元素的集合。特点是: **唯一, 无序**

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

> 解释:

>

> 1. 唯一的意思是Set中的元素具有唯一性, 没有重复元素

> 2. 无序的意思是Set集中的元素, 添加顺序和取出顺序不一致

10.4.2 不可变集

> 不可变集指的是元素, 集的长度都不可变.

(1)语法

- 格式一: 创建一个空的不可变集

  ```scala

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

  ```

- 格式二: 给定元素来创建一个不可变集

  ```scala

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

  ```

#### 4.2.2 示例一: 创建不可变集

##### 需求

1. 定义一个空的整型不可变集.

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

3. 打印结果.

##### 参考代码

```scala

//案例: 演示不可变集.

object ClassDemo16 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个空的整型不可变集.

    val set1 = Set[Int]()

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

    val set2 = Set(1, 1, 3, 2, 4, 8)

    // 3. 打印结果.

    println(s"set 1 : $set1")

    println(s"set 2 : $set2")

  }

}

```

#### 4.2.3 示例二: 不可变集的常见操作

##### 格式

1. 获取集的大小(size)

2. 遍历集(和遍历数组一致)

3. 添加一个元素,生成一个新的Set(+)

4. 拼接两个集,生成一个新的Set(++)

5. 拼接集和列表,生成一个新的Set(++)

> 注意:

>

> 1. -(减号)表示删除一个元素, 生成一个新的Set

> 2. --表示批量删除某个集中的元素, 从而生成一个新的Set

##### 需求

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

2. 获取集的大小, 并打印结果.

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

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

5. 拼接另一个集Set(6, 7, 8), 生成新的集, 并打印.

6. 拼接一个列表List(6,7,8, 9), 生成新的集, 并打印.

##### 参考代码

```scala

//案例: 演示不可变集的常用操作.

object ClassDemo17 {

  def main(args: Array[String]): Unit = {

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

    val set1 = Set(1, 1, 2, 3, 4, 5)

    // 2. 获取集的大小

    println("set1 的长度为: " + set1.size)

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

    println("set1 集中的元素为: ")

    for (i <- set1) println(i)

    println("-" * 15)

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

    val set2 = set1 - 1

    println("set2 : " + set2)

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

    val set3 = set1 ++ Set(6, 7, 8)

    println("set3 : " + set3)

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

    val set4 = set1 ++ List(6, 7, 8, 9)

    println("set4 : " + set4)

  }

}

```

10.4.3 可变集

(1) 概述

 可变集指的是元素, 集的长度都可变, 它的创建方式和不可变集的创建方式一致,只不过需要先导入可变集类。

手动导入:

import scala.collection.mutable.Set

(2)示例

##### 需求

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

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

3. 添加元素6, 7, 8到可变集中

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

5. 从可变集中移除元素3, 5, 7

6. 打印结果.

##### 参考代码

```scala

import scala.collection.mutable

//案例: 演示可变集.

object ClassDemo18 {

  def main(args: Array[String]): Unit = {

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

    val set1 = mutable.Set(1, 2, 3, 4)

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

    set1 += 5

    // 3. 添加元素 6 , 7 , 8 到可变集中

    //set 1 ++= Set( 6 , 7 , 8 )

    set1 ++= List(6, 7, 8) //两种写法均可.

    // 4. 从可变集中移除元素 1

    set1 -= 1

    // 5. 从可变集中移除元素 3 , 5 , 7

    //set 1 - -= Set( 3 , 5 , 7 )

    set1 --= List(3, 5, 7) //两种写法均可.

    // 6. 打印结果.

    println(set1)

  }

}

10.5 映射

映射指的就是Map。它是由键值对(key, value)组成的集合。特点是: **键具有唯一性**, **但是值可以重复**. 在Scala中,Map也分为不可变Map和可变Map。

> 注意: 如果添加重复元素(即: 两组元素的键相同), 则会用新值覆盖旧值.

10.5.1 不可变Map

不可变Map指的是元素,长度都不可变.

语法

- 方式一: 通过箭头的方式实现.

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

- 方式二: 通过小括号的方式实现.

  val/var^ map^ =^ Map((键,^ 值),^ (键,^ 值),^ (键,^ 值),^ (键,^ 值)...)

需求

1. 定义一个映射,包含以下学生姓名和年龄数据: 张三 -> 23, 李四 -> 24, 李四 -> 40

2. 打印结果.

参考代码

//案例: 演示不可变Map

object ClassDemo19 {

  def main(args: Array[String]): Unit = {

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

    val map1 = Map("张三" -> 23, "李四" -> 24, "李四" -> 40)

    val map2 = Map(("张三", 23), ("李四", 24), ("李四", 40))

    // 2. 打印结果.

    println(s"map 1 : $map1")

    println(s"map 2 : $map2")

  }

}

10.5.2 可变Map

特点

可变Map指的是元素, 长度都可变. 定义语法与不可变Map一致, 只不过需要先手动导包:

import scala.collection.mutable.Map

需求

1. 定义一个映射,包含以下学生姓名和年龄数据: 张三 -> 23, 李四 -> 24

2. 修改张三的年龄为 30

3. 打印结果

参考代码

import scala.collection.mutable

//案例: 演示可变Map.

object ClassDemo20 {

  def main(args: Array[String]): Unit = {

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

    val map1 = mutable.Map("张三" -> 23, "李四" -> 24)

    val map2 = mutable.Map(("张三", 23), ("李四", 24))

    // 2. 修改张三的年龄为 30

    map1("张三") = 30

    // 3. 打印结果

    println(s"map 1 : $map1")

    println(s"map 2 : $map2")

  }

}

10.5.3 Map基本操作

#### 格式

1. `map(key)`: 根据键获取其对应的值, 键不存在返回None.

2. `map.keys`: 获取所有的键.

3. `map.values`: 获取所有的值.

4. 遍历map集合: 可以通过普通for实现.

5. `getOrElse`: 根据键获取其对应的值, 如果键不存在, 则返回指定的默认值.

6. `+号`: 增加键值对, 并生成一个新的Map.

> 注意: 如果是可变Map, 则可以通过+=或者++=直接往该可变Map中添加键值对元素.

7. `-号`: 根据键删除其对应的键值对元素, 并生成一个新的Map.

> 注意: 如果是可变Map, 则可以通过-=或者--=直接从该可变Map中删除键值对元素.

示例

1. 定义一个映射,包含以下学生姓名和年龄数据: 张三 -> 23, 李四 -> 24

2. 获取张三的年龄, 并打印.

3. 获取所有的学生姓名, 并打印.

4. 获取所有的学生年龄, 并打印.

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

6. 获取王五的年龄,如果王五不存在,则返回-1, 并打印.

7. 新增一个学生:王五, 25, 并打印结果.

8. 将李四从可变映射中移除, 并打印.

参考代码

import scala.collection.mutable

//案例: 演示Map的常见操作.

object ClassDemo21 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个映射,包含以下学生姓名和年龄数据: 张三 - > 23 , 李四 - > 24

    val map1 = mutable.Map("张三" -> 23, "李四" -> 24)

    // 2. 获取张三的年龄, 并打印.

    println(map1.get("张三"))

    // 3. 获取所有的学生姓名, 并打印.

    println(map1.keys)

    // 4. 获取所有的学生年龄, 并打印.

    println(map1.values)

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

    for ((k, v) <- map1) println(s"键:$k, 值:$v")

    println("-" * 15)

    // 6. 获取`王五`的年龄,如果`王五`不存在,则返回- 1 , 并打印.

    println(map1.getOrElse("王五", -1))

    println("-" * 15)

    // 7. 新增一个学生:王五, 25 , 并打印结果.

    /*

    不可变Map

    val map 2 = map1 + ("王五" -> 25 )

    println(s"map 1 : $map1")

    println(s"map 2 : $map2")

    */

    map1 += "王五" -> 25

    println(s"map 1 : $map1")

    // 8. 将`李四`从可变映射中移除, 并打印.

    map1 -= "李四"

    println(s"map 1 : $map1")

  }

}

10. 6. 迭代器(iterator)

10.6.1 概述

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

10.6.2 注意事项

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

> 迭代器中有两个方法:

hasNext方法: 查询容器中是否有下一个元素

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

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

即: 迭代完后保留在最后一个元素的位置. 再次使用则抛出NoSuchElementException

3. 可以使用while或者for来逐个获取元素.

10.6.3 示例

#### 需求

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

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

#### 参考代码

//案例: 演示迭代器

object ClassDemo22 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4, 5)

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

    // 2. 1 根据列表获取其对应的迭代器对象.

    val it = list1.iterator

    // 2. 2 判断迭代器中是否有下一个元素.

    while (it.hasNext)

    // 2. 3 如果有, 则获取下一个元素, 并打印.

      println(it.next)

    //分割线.

    println("-" * 15)

    //迭代完后, 再次使用该迭代器获取元素, 则抛异常: NoSuchElementException

    println(it.next)

  }

}

10.7. 函数式编程

- 所谓的函数式编程指定就是方法的参数列表可以接收函数对象.

- 例如: add(10, 20)就不是函数式编程, 而add(函数对象)这种格式就叫函数式编程.

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

| 函数名   | 功能                           |

| -------- | ------------------------------ |

| foreach  | 用来遍历集合的                 |

| map      | 用来对集合进行转换的           |

| flatmap  | 用来对集合进行映射扁平化操作   |

| filter   | 用来过滤出指定的元素           |

| sorted   | 用来对集合元素进行默认排序     |

| sortBy   | 用来对集合按照指定字段排序     |

| sortWith | 用来对集合进行自定义排序       |

| groupBy  | 用来对集合元素按照指定条件分组 |

| reduce   | 用来对集合元素进行聚合计算     |

| fold     | 用来对集合元素进行折叠计算     |

10.7.1遍历(foreach)

示例一:foreach

采用foreach来遍历集合, 可以让代码看起来更简洁, 更优雅.

格式

  def foreach(f:(A) => Unit): Unit

  //简写形式

  def foreach(函数)

#### 说明

| foreach | API           | 说明                                                 |

| ------- | ------------- | ---------------------------------------------------- |

| 参数    | f: (A) ⇒ Unit | 接收一个函数对象, 函数的参数为集合的元素,返回值为空 |

| 返回值  | Unit          | 表示foreach函数的返回值为: 空                        |

#### 执行过程

![foreach](pictures/foreach.png)

#### 需求

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

#### 参考代码

```scala

//案例: 演示foreach函数

object ClassDemo23 {

  def main(args: Array[String]): Unit = {

    // 1. 定义一个列表, 包含 1 , 2 , 3 , 4

    val list1 = List(1, 2, 3, 4)

    // 2. 通过foreach函数遍历上述的列表.

    //x:表示集合中的每个元素 函数体表示输出集合中的每个元素.

    list1.foreach((x:Int) => {println(x)})

    println("*" * 15)

    //简写版本

    list1.foreach(x => println(x))

  }

}

示例二: 简化函数定义

#### 概述

上述案例函数定义有点啰嗦,我们有更简洁的写法。可以通过如下两种方式来简化函数定义:

 方式一: 通过类型推断来简化函数定义.

 解释:因为使用foreach来迭代列表,而列表中的每个元素类型是确定的, 所以我们可以通过类型推断让Scala程序来自动推断出来集合中每个元素参数的类型, 即: 在我们创建函数时,可以省略其参数列表的类型.

- 方式二: 通过下划线来简化函数定义.

> 解释:

>

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

#### 示例

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

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

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

#### 参考代码

```scala

//案例: 演示简化函数定义.

object ClassDemo24 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4)

    list1.foreach((x: Int) => println(x))

    println("-" * 15)

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

    list1.foreach(x => println(x))

    println("-" * 15)

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

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

    list1.foreach(println(_))

  }

}

10.7.2映射(map)

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

> 例如: 把List[Int]转换成List[String].

#### 格式

```scala

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

  //简写形式:

  def map(函数对象)

```

#### 说明

| map方法 | API                | 说明                                                         |

| ------- | ------------------ | ------------------------------------------------------------ |

| 泛型    | [B]                | 指定map方法最终返回的集合泛型, 可省略不写                    |

| 参数    | f: (A) ⇒ B         | 函数对象, 参数列表为类型A(要转换的列表元素),返回值为类型B |

| 返回值  | TraversableOnce[B] | B类型的集合, 可省略不写.                                     |

#### 执行过程

![映射](pictures/映射.png)

#### 需求

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

2. 将上述的数字转换成对应个数的*, 即: 1变为*, 2变为**, 以此类推.

#### 参考代码

```scala

//案例: 演示map函数(映射)

object ClassDemo25 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(1, 2, 3, 4)

    // 2. 将上述的数字转换成对应个数的`*`, 即: 1 变为*, 2 变为**, 以此类推.

    //方式一: 普通写法

    val list2 = list1.map((x: Int) => "*" * x)

    println(s"list 2 : $list2")

    //方式二: 通过类型推断实现.

    val list3 = list1.map(x => "*" * x)

    println(s"list 3 : $list3")

    //方式三: 通过下划线实现.

    val list4 = list1.map("*" * _)

    println(s"list 4 : $list4")

  }

}

```

10.7.3扁平化映射(flatMap)

扁平化映射可以理解为先map,然后再flatten, 它也是将来用得非常多的操作,也是必须要掌握的, 如图:

![扁平化映射](pictures/扁平化映射.png)

> 解释:

>

> 1. map是将列表中的元素转换为一个List

>

> 2. flatten再将整个列表进行扁平化

#### 格式

```scala

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

  //简写形式:

  def flatMap(f:(A) => 要将元素A转换成的集合B的列表)

```

#### 说明

| flatmap方法 | API                            | 说明                                                         |

| ----------- | ------------------------------ | ------------------------------------------------------------ |

| 泛型        | [B]                            | 最终要返回的集合元素类型, 可省略不写.                        |

| 参数        | f: (A) ⇒ GenTraversableOnce[B] | 传入一个函数对象<br />函数的参数是集合的元素<br />函数的返回值是一个集合 |

| 返回值      | TraversableOnce[B]             | B类型的集合                                                  |

#### 示例

#### 需求

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

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

#### 思路分析

![思路分析](pictures/思路分析.png)

#### 参考代码

```scala

//案例: 演示映射扁平化(flatMap)

object ClassDemo26 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List("hadoop hive spark flink flume", "kudu hbase sqoop storm")

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

    //方式一: 通过map, flatten实现.

    val list2 = list1.map(_.split(" "))

    val list3 = list2.flatten

    println(s"list 3 : $list3")

    //方式二: 通过flatMap实现.

    val list4 = list1.flatMap(_.split(" "))

    println(s"list 4 : $list4")

  }

}

```

10.7.4过滤(filter)

过滤指的是过滤出(筛选出)符合一定条件的元素.

#### 格式

```scala

  def filter(f:(A) => Boolean): TraversableOnce[A]

  //简写形式:

  def filter(f:(A) => 筛选条件)

```

#### 说明

| filter方法 | API                | 说明                                                         |

| ---------- | ------------------ | ------------------------------------------------------------ |

| 参数       | f: (A) ⇒ Boolean   | 传入一个函数对象<br />接收一个集合类型的参数<br />返回布尔类型,满足条件返回true, 不满足返回false |

| 返回值     | TraversableOnce[A] | 符合条件的元素列表                                           |

#### 执行过程

![filter](pictures/filter.png)

#### 案例

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

2. 请过滤出所有的偶数

#### 参考代码

```scala

//案例: 演示过滤(filter)

object ClassDemo27 {

  def main(args: Array[String]): Unit = {

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

    val list1 = (1 to 9).toList

    // 2. 请过滤出所有的偶数

    val list2 = list1.filter(_ % 2 == 0)

    println(s"list 2 : $list2")

  }

}

```

10.7.5排序(sorted、sortBy、sortWith)

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

| 函数名   | 功能                       |

| -------- | -------------------------- |

| sorted   | 用来对集合元素进行默认排序 |

| sortBy   | 用来对集合按照指定字段排序 |

| sortWith | 用来对集合进行自定义排序   |

(1)默认排序(sorted)

所谓的默认排序指的是对列表元素按照升序进行排列. 如果需要降序排列, 则升序后, 再通过reverse实现.

#### 需求

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

2. 对列表进行升序排序

3. 对列表进行降序排列.

#### 参考代码

```scala

//案例: 演示默认排序(sorted)

object ClassDemo28 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(3, 1, 2, 9, 7)

    // 2. 对列表进行升序排序

    val list2 = list1.sorted

    println(s"list 2 : $list2")

    // 3. 对列表进行降序排列.

    val list3 = list2.reverse

    println(s"list 3 : $list3")

  }

}

```

```c

#include <stdio.h>

void main(){

    int num;

    float money,price;

       printf("请输入货物数量:");

    scarf("%d",&num);

       printf("货物总价为:");

    price=2.5;

       money=mm*price;

       prirtf("money=%.1f元",money);

}

```

(2)指定字段排序(sortBy)

所谓的指定字段排序是指对列表元素根据传入的函数转换后,再进行排序.

> 例如: 根据列表List("01 hadoop", "02 flume")的 字母进行排序.

#### 格式

```scala

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

  //简写形式:

  def sortBy(函数对象)

```

#### 说明

| sortBy方法 | API        | 说明                                                         |

| ---------- | ---------- | ------------------------------------------------------------ |

| 泛型       | [B]        | 排序字段的数据类型.                                          |

| 参数       | f: (A) ⇒ B | 传入函数对象<br />接收一个集合类型的元素参数<br />返回B类型的元素进行排序 |

| 返回值     | List[A]    | 返回排序后的列表                                             |

#### 示例

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

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

#### 参考代码

```scala

//案例: 演示根据指定字段排序(sortBy)

object ClassDemo29 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(" 01 hadoop", " 02 flume", " 03 hive", " 04 spark")

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

    //val list 2 = list 1 .sortBy(x => x.split(" ")( 1 ))

    //简写形式:

    val list2 = list1.sortBy(_.split(" ")(1))

    println(s"list 2 : $list2")

  }

}

```

(3)自定义排序(sortWith)

所谓的自定义排序指的是根据一个自定义的函数(规则)来进行排序.

#### 格式

```scala

  def sortWith(f: (A, A) => Boolean): List[A]

  //简写形式:

  def sortWith(函数对象: 表示自定义的比较规则)

```

#### 说明

| sortWith方法 | API                 | 说明                                                         |

| ------------ | ------------------- | ------------------------------------------------------------ |

| 参数         | f: (A, A) ⇒ Boolean | 传入一个比较大小的函数对象<br />接收两个集合类型的元素参数<br />返回两个元素大小,小于返回true,大于返回false |

| 返回值       | List[A]             | 返回排序后的列表                                             |

#### 示例

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

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

#### 参考代码

```scala

//案例: 演示自定义排序(sortWith)

object ClassDemo30 {

  def main(args: Array[String]): Unit = {

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

    val list1 = List(2, 3, 1, 6, 4, 5)

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

    var list2 = list1.sortWith((x, y) => x > y) //降序

    //简写形式:

    //第一个下划线相当于上面的: x

    //第二个下划线相当于上面的: y

    list2 = list1.sortWith(_ > _) //降序

    println(s"list 2 : $list2")

  }

}

```

10.7.6分组(groupBy)

分组指的是将数据按照指定条件进行分组, 从而方便我们对数据进行统计分析.

#### 格式

```scala

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

  //简写形式:

  def groupBy(f:(A) => 具体的分组代码)

```

#### 说明

| groupBy方法 | API             | 说明                                                         |

| ----------- | --------------- | ------------------------------------------------------------ |

| 泛型        | [K]             | 分组字段的类型                                               |

| 参数        | f: (A) ⇒ K      | 传入一个函数对象<br />接收集合元素类型的参数<br />按照K类型的key进行分组,相同的key放在一组中, 并返回结果. |

| 返回值      | Map[K, List[A]] | 返回一个映射,K为分组字段,List为这个分组字段对应的一组数据  |

#### 执行过程

![分组](pictures/分组.png)

#### 需求

1. 有一个列表,包含了学生的姓名和性别: "刘德华" -> "男", "刘亦菲" -> "女", "胡歌" -> "男"

2. 请按照性别进行分组.

3. 统计不同性别的学生人数.

#### 参考代码

```scala

//案例: 演示分组函数(groupBy)

object ClassDemo31 {

  def main(args: Array[String]): Unit = {

    // 1. 有一个列表,包含了学生的姓名和性别: "刘德华" - > "男", "刘亦菲" - > "女", "胡歌" - > "男"

    val list1 = List("刘德华" -> "男", "刘亦菲" -> "女", "胡歌" -> "男")

    // 2. 请按照性别进行分组.

    //val list 2 = list 1 .groupBy(x => x._ 2 )

    //简写形式

    val list2 = list1.groupBy(_._2)

    //println(s"list 2 : ${list 2 }")

    // 3. 统计不同性别的学生人数.

    val list3 = list2.map(x => x._1 -> x._2.size)

    println(s"list3 : $list3")

  }

}

```

10.7.7聚合操作

所谓的聚合操作指的是将一个列表中的数据合并为一个. 这种操作经常用来统计分析中. 常用的聚合操作主要有两个:

- reduce: 用来对集合元素进行聚合计算

- fold: 用来对集合元素进行折叠计算

(1)聚合(reduce)

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

#### 格式

```scala

  def reduce[A 1 >: A](op:(A 1 , A 1 ) ⇒ A 1 ): A 1

  //简写形式:

  def reduce(op:(A 1 , A 1 ) ⇒ A 1 )

```

#### 说明

| reduce方法 | API               | 说明                                                         |

| ---------- | ----------------- | ------------------------------------------------------------ |

| 泛型       | [A1 >: A]         | (下界)A1必须是集合元素类型的父类, 或者和集合类型相同       |

| 参数       | op: (A1, A1) ⇒ A1 | 传入函数对象,用来不断进行聚合操作<br />第一个A1类型参数为:当前聚合后的变量<br />第二个A1类型参数为:当前要进行聚合的元素 |

| 返回值     | A1                | 列表最终聚合为一个元素                                       |

> 注意:

>

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

>

> reduceRight表示从右到左计算

#### 需求

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

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

#### 参考代码

```scala

//案例: 演示聚合计算(reduce)

object ClassDemo32 {

  def main(args: Array[String]): Unit = {

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

    val list1 = (1 to 10).toList

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

    //val list 2 = list 1 .reduce((x, y) => x + y)

    //简写形式:

    val list2 = list1.reduce(_ + _)

    val list3 = list1.reduceLeft(_ + _)

    val list4 = list1.reduceRight(_ + _)

    println(s"list2 : $list2")

    println(s"list3 : $list3")

    println(s"list4 : $list4")

  }

}

```

#### 7.8.2 折叠(fold)

fold与reduce很像,只不过多了一个指定初始值参数.

#### 格式

```scala

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

  //简写形式:

  def fold(初始值)(op:(A 1 , A 1 ) => A 1 )

```

#### 说明

| fold方法 | API              | 说明                                                         |

| -------- | ---------------- | ------------------------------------------------------------ |

| 泛型     | [A1 >: A]        | (下界)A1必须是集合元素类型的父类                           |

| 参数     | z: A1            | 初始值                                                       |

| 参数 2   | op: (A1, A1) ⇒ A | 传入函数对象,用来不断进行折叠操作<br />第一个A1类型参数为:当前折叠后的变<br />第二个A1类型参数为:当前要进行折叠的元 |

| 返回值   | A1               | 列表最终折叠为一个元素                                       |

> 注意事项:

>

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

> - foldRight表示从右往左计算

#### 需求

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

2. 假设初始化值是100, 使用fold方法计算所有元素的和.

#### 参考代码

```scala

//案例: 演示折叠计算(fold)

object ClassDemo33 {

  def main(args: Array[String]): Unit = {

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

    val list1 = (1 to 10).toList

    // 2. 假设初始化值是 100 , 使用fold计算所有元素的和

    //val list 2 = list 1 .fold( 100 )((x, y) => x + y)

    //简写形式:

    val list2 = list1.fold(100)(_ + _)

    val list3 = list1.foldLeft(100)(_ + _)

    val list4 = list1.foldRight(100)(_ + _)

    println(s"list 2 : $list2")

    println(s"list 3 : $list3")

    println(s"list 4 : $list4")

  }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值