概述
- 集合本质上就是一个用于存储1个到多个数据的容器。在Scala中,集合可以分为三大类: Seq (序
列), Set (集合)和 Map (映射)。基于这三大类,衍生出来众多的子类 - 序列:元素有序可重复
- 集合:元素无序不可重复
- 映射:键值对结构数据
- 在Scala中,所有的集合都混入了 Iterable 特质,意味着所有的集合都可以被迭代遍历
- Scala中的集合分为可变集合( scala.collection.mutable )和不可变集合
( scala.collection.immutable ) - 所谓的不可变集合,指的是集合被创建好之后,长度不可变,且其中的元素也不能改变。如
果对不可变集合中的元素进行增删操作,那么不会改变原集合,而是会产生一个新的集合 - 所谓的可变集合,指的是集合创建好之后,依然可以对元素进行增删操作,并且不会产生新
集合,而是修改原集合
数组
不可变数组( Array ) - 不可变数组定义好之后,长度不能发生变化,元素也不能增删;如果增删元素,那么会产生一个新
的数组 - 定义方式
package com.fesco.array
object ArrayDemo {
def main(args: Array[String]): Unit = {
// 不可变数组定义方式
// 方式一:val 数组名:Array[元素类型] = new Array[元素类型](数组长度)
// 数组定义好之后,每一个位置都会有默认值
val arr: Array[Int] = new Array[Int](5)
arr(0) = 3
// 将数组转化为字符串
println(arr.mkString(","))
// 方式二:
// int[] arr = new int[]{3,4,1,4,5}
val arr2: Array[Int] = Array(3, 1, 7, 8, 4)
println(arr2.mkString(","))
}
}
- 应用一
package com.fesco.array
object ArrayDemo2 {
def main(args: Array[String]): Unit = {
// 不可变数组定义好之后长度不可变
val arr = Array(2, 4, 8, 7, 1, 5, 6)
// 应用一:修改数组中元素的值
// 方式一:数组名(下标) = 数据
arr(3) = 4
// 方式二:提供了update方法来修改元素数据
arr.update(2, 5)
// 应用二:遍历数组
// 方式一:转化为字符串
val str = arr.mkString(", ")
println(str)
// 方式二:通过下标来遍历
for (i <- 0 until arr.length) println(arr(i))
// 方式三:增强for循环
// 增强for循环本质上就是在对元素进行迭代遍历
for (i <- arr) println(i)
// 方式四:迭代遍历
val it = arr.iterator
while (it.hasNext) println(it.next())
// 方式五:foreach方法
arr.foreach(x => println(x))
// 顺次使用参数,并且参数只使用了一次
arr.foreach(println(_))
// println(3,5, (x, y) => x+ y)
// println(3,5, _ + _ )
// 函数体只有一句,并且使用了已经存在函数,且参数是一一对应,那么此时参数列表可以省略
arr.foreach(println)
}
} - 应用二
package com.fesco.array
object ArrayDemo3 {
def main(args: Array[String]): Unit = {
val arr = Array(2, 4, 8, 7, 1, 5, 6)
// 应用三:数组扩容
// Array类中提供了+:和:+的方式来对数组进行扩容,本质上都是产生一个新的数组
// :+ 在数组的末尾来新添元素,构成一个新的数组
val r1 = arr :+ 3
println(r1.mkString(", "))
// +: 在数组的头部来新添元素,构成一个新的数组
val r2 = arr.+:(3)
println(r2.mkString(", "))
val r3 = 3 +: arr
println(r3.mkString(", "))
val r4 = 4 +: arr :+ 3
println(r4.mkString(", "))
// 应用四:数组合并
val nums1 = Array(1, 2, 3, 4, 5)
val nums2 = Array(6, 7, 8, 9)
// 方式一:通过++合并
val v1 = nums1 ++ nums2
println(v1.mkString(", "))
// 方式二: ++: 或者 :++
// ++:等价于++
val v2 = nums1 ++: nums2
println(v2.mkString(", "))
val v3 = nums1 :++ nums2
println(v3.mkString(", "))
// 方式三:concat函数
val v4 = nums1.concat(nums2)
println(v4.mkString(", "))
}
} - 应用三
package com.fesco.array
object ArrayDemo4 {
def main(args: Array[String]): Unit = {
// 应用五:创建连续范围的数组
val r1 = Array.range(1, 5)
println(r1.mkString(", "))
val r2 = Array.range(0, 10, 2)
println(r2.mkString(", "))
// 应用六:用指定数据来填充数组
// 创建数组,数组的所有元素默认为10
// 第一个()表示数组长度
// 第二个()表示填充的元素
val v1 = Array.fill(5)(10)
println(v1.mkString(", "))
// 填充由100以内的随机数构成的长度为7的数组
val v2 = Array.fill(7)((Math.random() * 100).toInt)
println(v2.mkString(", "))
// ({})可以选择省略()或者{}
val v3 = Array.fill(7) { - 练习:猴子报数。15只猴子围成一圈报数,报到数字7的猴子被淘汰,下一只猴子从1重新报数,
最后剩余的是哪只猴子?
可变数组( ArrayBuffer )
(Math.random() * 100).toInt
}
println(v3.mkString(", "))
// 应用七:数组翻转
val v4 = v3.reverse
println(v4.mkString(", "))
}
}
package com.fesco.array
object MonkeyExec {
def main(args: Array[String]): Unit = {
// 定义数组,表示15只猴子
// 用true表示猴子的还活着,用false表示猴子被淘汰
val monkeys = Array.fill(15)(true)
// 定义变量来记录还剩余的猴子数量
var n = 15
// 定义变量来记录报数
var i = 1
// 定义变量来记录下标
var index = 0
// 只要剩余的猴子数量>1那么就需要继续报数
while (n > 1) {
// 先判断这只猴子是否存活
if (monkeys(index)) {
// 判断这只猴子是否会被淘汰
if (i == 7) {
// 这只猴子被淘汰
monkeys(index) = false
// 剩余猴子数量-1
n -= 1
// 下一只猴子重新报数
i = 0
}
// 报数+1
i += 1
}
// 下一只猴子准备
index += 1
if (index == monkeys.length) index = 0
}
println(monkeys.mkString(", "))
}
} - 可变数组,类似于Java中的 ArrayList ,长度可以发生变化,并且可以对数组中的元素来进行增
删 - 定义格式
package com.fesco.array
import scala.collection.mutable.ArrayBuffer
object ArrayBufferDemo {
def main(args: Array[String]): Unit = {
// 定义方式
// 方式一:创建了可变数组,初始大小为0
val r1 = new ArrayBuffer[Int]
r1.+=(5)
r1 += 3
println(r1)
// 方式二:创建可变数组,指定初始大小
val r2 = new ArrayBufferInt
r2 += 4
r2 += 2
r2 += 5
r2 += 7
println(r2)
// 方式三:创建可变数组,传入初始元素
val r3 = ArrayBuffer[Int](2, 7, 8, 9, 1)
println(r3)
}
} - 基本操作
package com.fesco.array
import scala.collection.mutable.ArrayBuffer
object ArrayBufferDemo2 {
def main(args: Array[String]): Unit = {
val arr = ArrayBuffer[Int](3, 4, 5, 6, 7)
// 在末尾添加元素
arr.+=(8)
arr += 9
arr.append(10)
println(arr)
// 在头部添加元素
arr.prepend(2)
println(arr)
1 +=: arr
println(arr)
// 插入元素
转换
多维数组 - 定义格式
arr.insert(2, 11)
println(arr)
// 修改元素
arr(0) = 0
println(arr)
arr.update(1, 3)
println(arr)
// 删除指定下标上的元素
arr.remove(0)
println(arr)
// 删除元素3
// 删除指定的元素(第一次出现)
arr -= 3
println(arr)
// 遍历
arr.foreach(println)
}
}
package com.fesco.array
import scala.collection.mutable.ArrayBuffer
object ArrayTransformDemo {
def main(args: Array[String]): Unit = {
// 可变数组 -> 不可变数组
val arrBuffer = ArrayBuffer[Int](2, 3, 4, 5)
val arr = arrBuffer.toArray
println(arr)
// 不可变数组 -> 可变数组
val array = Array[Int](1, 2, 3, 4, 5)
val buffer = array.toBuffer
println(buffer)
}
}
package com.fesco.array
object DimensionDemo {
def main(args: Array[String]): Unit = {
// 定义格式
// 方式一:
// 定义二维数组r1,包含了3个一维数组,每一个一维数组的大小是不确定的
val r1: Array[Array[Int]] = new ArrayArray[Int]
r1(0) = new ArrayInt
r1(1) = Array[Int](1, 2, 3, 4)
// 方式二:
// 定义二维数组r2包含了2个一维数组
val r2 = Array(Array(1, 2, 3), Array(1, 3, 4, 6))
println(r2(0)(1))
// 方式三:
// 通过ofDim函数来构建二维数组
// 定义二维数组r3,包含了3个一维数组,每一个一维数组包含了5个元素
val r3 = Array.ofDim[Int](3, 5)
r3(0)(0) = 3
println(r3(0)(0))
// 一维数组,可以包含4个整数
val r4 = Array.ofDimInt
// 三维数组,包含了4个二维数组,每一个二维数组中包含了3个一维数组,每一个一维数组可以
包含5个整数
var r5 = Array.ofDim[Int](4, 3, 5)
// 四维数组,包含了3个三维数组,每一个三维数组中包含了4个二维数组,每一个二维数组中包
含了5个一维数组,每一个一维数组可以有2个整数
var r5 = Array.ofDim[Int](3, 4, 5, 2)
}
} - 如果每一个一维数组等大,那么推荐使用第三种方式;如果包含的一维数组不等大,使用方式一;
如果已知元素,那么使用方式二 - ofDim 支持多维数组:一维~五维数组。Scala中不推荐超过5维的数组
- 练习:输入一个数字n表示行数,输出杨辉三角的前n行
package com.fesco.array
import scala.io.StdIn
object DimensionExec {
def main(args: Array[String]): Unit = {
/*
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
...
*/
// 获取整数n
val n = StdIn.readInt()
// 定义二维数组
列表
不可变列表( List ) - 在Scala中,通过 List 来定义不可变列表,需要注意的是,List本身是一个抽象类,所以并不能直
接使用List来构建对象,需要使用它的伴生对象来构建
val arr = new ArrayArray[Int]
// 遍历数组
for (i <- 0 until n) {
// 初始化第i行一维数组
arr(i) = new Array[Int](i + 1)
// 填充元素
for (j <- 0 to i) {
// 每一行第一个或者最后一个元素是1
if (j == 0 || j == i) arr(i)(j) = 1
else arr(i)(j) = arr(i - 1)(j) + arr(i - 1)(j - 1)
}
println(arr(i).mkString("\t"))
}
}
}
package com.fesco.list
import scala.::
object ListDemo {
def main(args: Array[String]): Unit = {
// 方式一
val list = List[Int](2, 3, 4, 5, 6)
println(list)
val list2 = List.apply(2, 3, 4, 5, 6)
println(list2)
// 方式二:
// :: 在list之前来追加数据
val list3 = 1 :: list
println(list3)
// 方式三:
// Nil是List的子类,表示一个空列表
val list4 = Nil
println(list4)
// 方式四:
val list5 = 1 :: 2 :: 3 :: 4 :: Nil
println(list5)
}
} - List被 sealed 修饰,说明List是一个密封类,那么就意味着List的子类必须和List处在同一个scala
文件中,即List无法直接扩展 - 基本操作
package com.fesco.list
object ListDemo2 {
def main(args: Array[String]): Unit = {
val list = List[Int](3, 4, 8, 1, 5, 9, 7)
// 获取指定下标位置上的元素
// 底层实际上是调用了父特质LinearSeq中的apply函数
println(list(2))
// 等价于
println(list.apply(2))
// 获取第一个元素
// println(list(0))
// 等价于
println(list.head)
// 获取最后一个元素
println(list.last)
// 追加一个元素 - 产生一个新的列表
// val r1 = list :+ 6
val r1 = list.:+(6)
println(r1)
// 在头部追加元素
// 从右向左计算
val r2 = 1 +: list
// val r2 = list.+:(1)
// 当出现:的时候,:对着谁就从谁开始计算
// 如果两边都有:,那么从右向左计算
// 错误的写法:list +: 1
println(r2)
// 或者
// val r3 = list.::(1)
val r3 = 1 :: list
// list :: 1
println(r3)
// 构建了列表
// 从右到左:先构建空列表List(),然后头部拆入5,在插入4
val r4 = 1 :: 2 :: 3 :: 4 :: 5 :: List()
// 等价于
val r5 = 1 :: 2 :: 3 :: 4 :: 5 :: Nil
println(r4)
println(r5)
}
} - 列表的合并
package com.fesco.list
可变列表( ListBuffer ) - Scala中,通过ListBuffer来定义可变列表
- 基本操作
object ListDemo3 {
def main(args: Array[String]): Unit = {
val list1 = List[Int](1, 2, 3, 4)
val list2 = List[Int](5, 6, 7, 8)
// 合并列表
val r1 = list1 ++ list2
println(r1)
val r2 = list1 ++: list2
println(r2)
val r3 = list1 :++ list2
println(r3)
val r4 = list1.concat(list2)
println(r4)
val r5 = list1 ::: list2
println(r5)
}
}
package com.fesco.list
import scala.collection.mutable.ListBuffer
object ListBufferDemo {
def main(args: Array[String]): Unit = {
// 方式一
// 调用ListBuffer类的主构造器
val buffer1 = new ListBufferInt
buffer1 += 4
println(buffer1)
// 方式二
// 调用了ListBuffer伴生对象中的apply函数
val buffer2 = ListBuffer[Int](1, 2, 3, 4, 5)
println(buffer2)
}
}
package com.fesco.list
import scala.collection.mutable.ListBuffer
object ListBufferDemo2 {
def main(args: Array[String]): Unit = {
val list = ListBuffer[Int](1, 2, 3, 4, 5)
// 在尾部追加元素
list += 4
list append 7
println(list)
// 在头部插入元素
list prepend 0
// list.+=:(2)
2 +=: list
println(list)
// 在指定下标位置上插入元素
list.insert(3, 6)
println(list)
// 修改指定位置上的元素
list(2) = 10
list.update(3, 12)
println(list)
// 删除指定下标位置上的元素
list.remove(0)
println(list)
// 删除指定的元素(第一个)
list -= 3
println(list)
}
} - 合并列表
package com.fesco.list
import scala.collection.mutable.ListBuffer
object ListBufferDemo3 {
def main(args: Array[String]): Unit = {
val list1 = ListBuffer[Int](1, 2, 3)
val list2 = ListBuffer[Int](4, 5, 6)
// 将list1和list2合并
// ++合并之后产生一个新的列表,而不是修改原列表
val r1 = list1 ++ list2
println(r1)
// 要求:将list2中的数据合并到list1中
list1 ++= list2
println(list1)
// 获取list1中有而list3中没有的数据 - 差集
val list3 = ListBuffer[Int](1, 3, 5, 7)
list1 --= list3
println(list1)
}
}