Scala(四)

Scala 四

集合

  1. Scala有三大集合: Seq序列, Set集, Map映射, 所有的集合都扩展自 Iterable特质
  2. Scala对几乎所有的集合类, 提供了可变和不可变的版本, 部分可变和不可变集合名称相同(*可通过包名称知晓集合类型
    2-1) 不可变集合: scala.collection.immutable
    2-2) 可变集合: scala.collection.mutable
  3. Scala不可变集合, 是指集合元素不可修改, 如果修改了集合元素就会返回一个新的集合, 而原有集合元素不会被改动. 类似 Java的 String对象
  4. 可变集合, 就是可以直接对原有集合元素进行增删改操作. 类似于 Java的 StringBuilder对象

*集合增删操作函数使用建议: 不可变集合使用(+-=:)的符号函数, 可变集合使用英文名称的函数

  • 不可变集合继承图:

Scala(四)

  • 可变集合继承图:

Scala(四)

*在 Scala List归属到 Seq下, Seq的直接子级有 IndexedSeq(索引序列)和 LinearSeq(线性序列)

  • IndexedSeq和 LinearSeq的区别:
  1. IndexedSeq是通过索引来查找和定位的 如 String就是一个索引集合, 通过索引即可定位
  2. LinearSeq是线型的, 即有头尾的概念, 这种数据结构一般是通过遍历来查找

数组(Array/ArrayBuffer)

  • 数组属 Seq特征, 直属上级特征为 IndexedSeq(索引序列)

不可变数组: Array(Scala推荐使用不可变数组

  • Scala: Array[Int](对应 Java是 int[]或 List
  • 查看 Array类源码, 可以发现直接父级是没有实现 IndexedSeq特征的, 但其实 Scala编译时, 将 Array在 Predef.scala中隐式转型成 abstract class WrappedArrayT抽象类(这个类实现了 IndexedSeq特征), 所以 Array可以使用 IndexedSeq特征的所有方法(可以理解为隐式实现 IndexedSeq特征)
  • *数组的不可变是指大小(元素个数), 已有元素的值是可以修改的
  • *新增元素的函数中(:)必须朝向数组本身, 再使用符号(+)朝向要新增的元素值; 在这里元素值在前在后决定元素加到数组的末尾还是首位
  • 创建方式有两种:
  1. val arr1 = new ArrayInt // 通过 new关键字(指定数据类型, 任意类型, 则 Any; 并指定大小(元素个数)
  2. val arr2 = Array(1,2,3) // 通过伴生对象
package com.ex4.test1

object Test1 {
  def main(args: Array[String]): Unit = {
    // 通过 new关键字创建数组
    val arr1 = new Array[Int](3)
    arr1(0) = 8 // 索引位0的元素值改为8(Scala编译时将代码该写成 arr1.update(0, 8)
    println(arr1) // [I@4c203ea1 输出的是地址, 因为 Array, 没有 toString()方法
    println(arr1.mkString(",")) // 8,0,0
    // 通过伴生对象创建数组(推荐
    val arr2 = Array(5,6,7)
    println(arr2.mkString(",")) // 5,6,7

    // 访问元素
    println(arr2(0)) // 5(获取索引位0的元素值 (Scala编译时会改写成 arr2.apply(0)

    // 修改元素值
    arr2(1) = 9 // 将索引位1的元素值更改为9
    println(arr2.mkString(",")) // 5,9,7
    // arr2(3) ArrayIndexOutOfBoundsException: 3 数组越界

    // 遍历数组 1
    for (i <- 0 until arr2.length) {
      print(arr2(i) + ",")
    }
    println()
    // 5,9,7,

    // 遍历数组 2 (遍历指定数组的所有索引
    println(arr2.indices.mkString(",")) // 0,1,2 输出所有索引
    for (i <- arr2.indices) print(arr2(i) + ",")
    println()
    // 5,9,7,

    // 遍历数组 3
    for (elem <- arr2) print(elem + ",")
    println()
    // 5,9,7,

    // 遍历数组 4(迭代器
    val iter = arr2.iterator
    while (iter.hasNext) print(iter.next() + ",")
    println()
    // 5,9,7,

    // 遍历数组 5(foreach方法
    //    arr2.foreach((elem: Int) => println(elem)) 匿名函数方式
    //    arr2.foreach(println) 简化匿名函数

    val arr3 = Array(35, "Shawn") // 类型为 Any
    for (elem <- arr3) print(elem + ",") // 35,Shawn,
    println()

    // 添加元素
    val newArr = arr2.:+(10) // 数组的末尾新加元素(不可变数组, 新加元素只能生成新的
    println(arr2.mkString(",")) // 5,9,7 不变
    println(newArr.mkString(",")) // 5,9,7,10

    val newArr2 = newArr.+:(30) // 数组的开始处插入新元素
    println(newArr2.mkString(",")) // 30,5,9,7,10

    // 将以上新增元素方式简化
    val newArr3 = newArr2 :+ 99 // 加到末尾(计算顺序为从左到右
    println(newArr3.mkString(",")) // 30,5,9,7,10,99

    // 计算函数中(:)必须朝向数组本身, 再加符号(+)朝向要新增的元素值; 在这里元素值在前在后决定元素加到数组的末尾还是首位
    // val newArr4 = newArr3 +: 11 // value +: is not a member of Int
    val newArr4 = 11 +: newArr3 // 加到首位(计算顺序为从右到左
    println(newArr4.mkString(",")) // 11,30,5,9,7,10,99

    // 前后可以同时进行加减
    val newArr5 = 33 +: 22 +: newArr4 :+ 999 :+ 9
    println(newArr5.mkString(", ")) // 33, 22, 11, 30, 5, 9, 7, 10, 99, 999, 9
  }
}

可变数组: ArrayBuffer

  • 继承自 IndexedSeq特征, 也就是有序的
package com.ex4.test2

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

object Test2 {
  def main(args: Array[String]): Unit = {
    val arr1: ArrayBuffer[Int] = new ArrayBuffer[Int]() // 通过 new关键字(无参创建, 默认长度为16
    println(arr1) // ArrayBuffer()
    val arr2 = ArrayBuffer(5, 4, 6) // 通过伴生对象
    println(arr2)  // ArrayBuffer(5, 4, 6)

    // 访问元素
    // println(arr1(0)) IndexOutOfBoundsException: 0 索引溢出
    println(arr2(1)) // 4 获取索引位1的元素值
    arr2(1) = 40 // 将索引位1的元素值更改为40
    println(arr2) // ArrayBuffer(5, 40, 6)

    // 添加元素
    // 1. 可变数组同样可以使用符号函数来计算, 但不建议这样用
    // 2. arr1追加元素值20, 但可变数组特点是修改自身的元素个数, 如按照以下方式计算, 效果是和不可变一样会创建新数组, 自身是不会变化的
    val newArr1 = arr1 :+ 20
    println(arr1) // ArrayBuffer() 依然是空数组
    println(newArr1) // ArrayBuffer(20)
    println(arr1 == newArr1) // false 新生成的数组和原数组不关联的

    arr1 += 30 // 可变数组追加并改自身元素个数(计算顺序为从左到右-往后追加
    println(arr1) // ArrayBuffer(30)

    15 +=: arr1 // 加到首位(计算顺序为从右到左-往前追加
    println(arr1) // ArrayBuffer(15, 30)

    // 可变集合建议用英文名称的函数
    arr1.append(400, 500, 600) // 加到后面
    arr1.prepend(100, 200, 300) // 加到前面
    println(arr1) // ArrayBuffer(100, 200, 300, 15, 30, 400, 500, 600)

    arr1.insert(1, 101, 102, 103) // 索引位1, 插入1个或多个元素
    println(arr1) // ArrayBuffer(100, 101, 102, 103, 200, 300, 15, 30, 400, 500, 600)

    arr1.insertAll(8, arr2) // 索引位8, 插入 arr2数组的所有元素
    println(arr1) // ArrayBuffer(100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 500, 600)
    arr1.prependAll(arr2) // 数组 arr1的开始处, 插入数组 arr2的所有元素;
    println(arr1) // ArrayBuffer(5, 40, 6, 100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 500, 600)

    // 删除元素
    arr1.remove(2) // 删除索引位2的元素
    println(arr1) // ArrayBuffer(5, 40, 100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 500, 600)

    arr1.remove(0, 2) // 删除索引位0, 开始2个元素(包含索引位0)
    println(arr1) // ArrayBuffer(100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 500, 600)

    arr1.append(500, 500, 500)
    println(arr1) // ArrayBuffer(100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 500, 600, 500, 500, 500)
    arr1 -= 500 // 删除值为500的元素, 每次只会删除一个, 优先删除越靠左的元素
    arr1 -= 500
    println(arr1) // ArrayBuffer(100, 101, 102, 103, 200, 300, 15, 30, 5, 40, 6, 400, 600, 500, 500)
  }
}

不可变数组与可变数组的转换

  1. toArray: 转换为不可变数组
  2. toBuffer: 转换为可变数组
package com.ex4.test3

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

object Test3 {
  def main(args: Array[String]): Unit = {
    val arr: ArrayBuffer[Int] = ArrayBuffer(2, 3, 1)
    val newArr: Array[Int] = arr.toArray // 可变数组转换为不可变数组
    println(arr) // ArrayBuffer(2, 3, 1)
    println(newArr.mkString(", ")) // 2, 3, 1

    val buffer: mutable.Buffer[Int] = newArr.toBuffer // 不可变数组转换为可变数组
    println(newArr.mkString(", ")) // 2, 3, 1
    println(buffer) // ArrayBuffer(2, 3, 1)
  }
}

多维数组

  • Scala最多支持5维数组
package com.ex4.test4

object Test4 {
  def main(args: Array[String]): Unit = {
    // 创建一维数组
    val arr1 = Array.ofDim[Int](2)
    arr1(1) = 10
    println(arr1.mkString(",")) // 0,10

    // 创建二维数组(最多可以创建5维数组
    val arr2: Array[Array[Int]] = Array.ofDim[Int](2, 3) // 2行3列
    // 访问元素
    arr2(0)(2) = 19
    arr2(1)(0) = 25
    println(arr2.mkString(", ")) // [I@17c68925, [I@7e0ea639
    for (i <- arr2.indices; j <- arr2(i).indices) {
      print(arr2(i)(j) + "\t")
      if (j == arr2(i).length - 1) println()
    }
    //    0   0   19
    //    25	0   0

    // 通过 lambda函数, 输出
    arr2.foreach(line => line.foreach(println))
    arr2.foreach(_.foreach(println))
  }
}

列表(List/ListBuffer)

  • 列表属 Seq特征, 直属上级特征为 LinearSeq(线性序列). 线性序列底层没有索引, 而是有头尾的概念, 以及需要查找元素时, 会通过遍历来解决

不可变列表: List

  1. List默认为不可变集合
  2. 数据有顺序, 可重复
  3. 创建只能通过伴生对象创建
  4. 源码上 sealed abstract class List[+A], 其中 sealed是声明该抽象类是密封类, 该类的子类只能定义在同一个 List.scals文件内, 无法在其它文件中导入继承该抽象类
  5. 底层没有索引, 但使用时, 可以索引的形式使用(该功能是在 LinearSeqOptimized特征的 apply方法, 通过遍历实现
  6. 但修改元素值时, 无法通过锁定索引的形式修改(例 list(1) = 123), 因为内部没有 update方法
  7. 空列表 Nil
  8. (::)这个函数用于新增元素, 只会加到前面(主要用于通过 Nil创建列表
  9. (::
上一篇:CentOS服务器安装jenkins自动化部署前端vue代码(三)-jenkins的安装


下一篇:跟韩老师学Java第二天(章)-Java概述