Scala
集合
概述
-
集合本质上就是一个用于存储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) { (Math.random() * 100).toInt } println(v3.mkString(", ")) // 应用七:数组翻转 val v4 = v3.reverse println(v4.mkString(", ")) } }
-
练习:猴子报数。15只猴子围成一圈报数,报到数字7的猴子被淘汰,下一只猴子从1重新报数,最后剩余的是哪只猴子?
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(", ")) } }
可变数组(ArrayBuffer
)
-
可变数组,类似于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 ArrayBuffer[Int](3) 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 Array[Array[Int]](3) r1(0) = new Array[Int](5) 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.ofDim[Int](4) // 三维数组,包含了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() // 定义二维数组 val arr = new Array[Array[Int]](n) // 遍历数组 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")) } } }
列表
不可变列表(List
)
-
在Scala中,通过
List
来定义不可变列表,需要注意的是,List本身是一个抽象类,所以并不能直接使用List来构建对象,需要使用它的伴生对象来构建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 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) } }
可变列表(ListBuffer
)
-
Scala中,通过ListBuffer来定义可变列表
package com.fesco.list import scala.collection.mutable.ListBuffer object ListBufferDemo { def main(args: Array[String]): Unit = { // 方式一 // 调用ListBuffer类的主构造器 val buffer1 = new ListBuffer[Int]() 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) } }