Scala详解(5)

Scala

集合

概述

  1. 集合本质上就是一个用于存储1个到多个数据的容器。在Scala中,集合可以分为三大类:Seq(序列),Set(集合)和Map(映射)。基于这三大类,衍生出来众多的子类

    1. 序列:元素有序可重复

    2. 集合:元素无序不可重复

    3. 映射:键值对结构数据

  2. 在Scala中,所有的集合都混入了Iterable特质,意味着所有的集合都可以被迭代遍历

  3. Scala中的集合分为可变集合(scala.collection.mutable)和不可变集合(scala.collection.immutable)

    1. 所谓的不可变集合,指的是集合被创建好之后,长度不可变,且其中的元素也不能改变。如果对不可变集合中的元素进行增删操作,那么不会改变原集合,而是会产生一个新的集合

    2. 所谓的可变集合,指的是集合创建好之后,依然可以对元素进行增删操作,并且不会产生新集合,而是修改原集合

数组

不可变数组(Array)
  1. 不可变数组定义好之后,长度不能发生变化,元素也不能增删;如果增删元素,那么会产生一个新的数组

  2. 定义方式

    复制代码
    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(","))
    ​
      }
    ​
    }
  3. 应用一

    复制代码
    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)
    ​
    ​
      }
    ​
    }
  4. 应用二

    复制代码
    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(", "))
    ​
      }
    ​
    }
  5. 应用三

    复制代码
    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(", "))
    ​
      }
    ​
    }
  6. 练习:猴子报数。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)
  1. 可变数组,类似于Java中的ArrayList,长度可以发生变化,并且可以对数组中的元素来进行增删

  2. 定义格式

    复制代码
    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)
    ​
      }
    ​
    }
  3. 基本操作

    复制代码
    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)
​
  }
​
}
多维数组
  1. 定义格式

    复制代码
    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)
    ​
      }
    ​
    }
  2. 如果每一个一维数组等大,那么推荐使用第三种方式;如果包含的一维数组不等大,使用方式一;如果已知元素,那么使用方式二

  3. ofDim支持多维数组:一维~五维数组。Scala中不推荐超过5维的数组

  4. 练习:输入一个数字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)
  1. 在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)
     
      }
    ​
    }
  2. List被sealed修饰,说明List是一个密封类,那么就意味着List的子类必须和List处在同一个scala文件中,即List无法直接扩展

  3. 基本操作

    复制代码
    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)
    ​
      }
    ​
    }
  4. 列表的合并

    复制代码
    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)
  1. 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)
    ​
      }
    ​
    }
  2. 基本操作

    复制代码
    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)
    ​
      }
    ​
    }
  3. 合并列表

    复制代码
    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)
    ​
      }
    ​
    }
相关推荐
码到成功>_<2 分钟前
Spring Boot实现License生成和校验
数据库·spring boot·后端
熬夜学编程的小王15 分钟前
【C++篇】从基础到进阶:全面掌握C++ List容器的使用
开发语言·c++·list·双向链表·迭代器失效
悄悄敲敲敲17 分钟前
C++:智能指针
开发语言·c++
书埋不住我23 分钟前
java第三章
java·开发语言·servlet
好开心3331 分钟前
javaScript交互案例2
开发语言·前端·javascript·html·ecmascript·交互
tian-ming34 分钟前
(十八)JavaWeb后端开发案例——会话/yml/过滤器/拦截器
java·开发语言·前端
Ztiddler43 分钟前
【npm设置代理-解决npm网络连接error network失败问题】
前端·后端·npm·node.js·vue
快意咖啡~44 分钟前
java.nio.charset.MalformedInputException: Input length = 1
java·开发语言·nio
李钢蛋1 小时前
PHP函数---function_exists()详解
开发语言·php
halo14161 小时前
uni-app 界面TabBar中间大图标设置的两种方法
开发语言·javascript·uni-app