五, Scala常见集合类总结(Array, List, Set, Map)
五, Scala常见集合类总结(Array, List, Set, Map)
5.1 Scala集合概述
- Scala 的集合有三大类: 序列seq, 集Set, 映射Map, 所有的集合都扩展自
Iterable特质;- 对于几乎所有的集合类, Scala都同时提供了可变和不可变的版本. 分别位于以下两个包: scala.collection.immutable, scala.collection.mutable
Q:什么是可变,不可变集合?
a. Scala 不可变集合, 就是指该集合对象不可修改, 每次修改就会返回一个新的对象引用, 而不会对原对象数据进行修改, 类似于java中的String对象, (改变对象的引用地址, 而不是直接修改原有引用地址中的数据)
b. Scala 可变集合, 指的是可以直接对原有的集合对象进行修改, 而不会返回新的对象, (类似于java中的StringBuffer对象)
- 在操作集合的时候, 推荐不可变用符号, 可变用方法(先记住这句话)
5.1.1 Scala 不可变集合继承图

- Seq 可细分为索引序列(indexed)和线性序列(indexed)。一般来说索引序列的访问速度比线性序列要快一些,但是线性序列的应用场景比较多,比如队列和栈等都是很常用的数据结构。
- Set和- Map都提供有序方式的集合- SortedXXX。Java 中- List归属于 Set 集合下,在 Scala 则属于 Seq 的线性序列部分。
- String被归纳到了索引序列下:因为它本质上可被认作是- Char[]类型集合,并且还可以通过索引的方式来输出对应位置的字符。
5.1.2 Scala 可变集合继承图

-  可变集合的内容明显要比不可变集合要更复杂一些,主要是多了 Buffer(缓冲)的内容。在实际开发中我们常用的有ArrayBuffer和ListBuffer。
-  如果涉及到线程安全的内容,则使用以 Synchronized作为前缀的集合。
5.2 数组 Array
- 数组是有序的,可以包含重复项,不可变(Array)或可变(ArrayBuffer)
5.2.1 不可变数组
[定义方法]
| 两种定义方法 | 解释 | 
|---|---|
| val arr1 = new ArrayInt | 1. new 是关键字; 2. [Int] 指定数组存放数据类型(泛型), [Any] 为任意类型; 3. (10) 表示数组的大小, 确定后不可变 | 
| val arr2 = Array(1,2) | 1. 定义数组时, 直接赋初始值; 2. 使用apply方法创建数组对象 | 
中括号[]表示泛型, 圆括号()表示数组长度
[不可变数组的增删改查和遍历方法]
| 写法 | 解释 | 
|---|---|
| arr(index) | 根据索引 访问数组arr的元素 | 
| :+ 尾部追加, +: 头部追加, ++ 连接两个集合, +++ 连接两个List | 向集合中 追加元素, 会生成新的数组, 冒号始终靠近集合变量一端 | 
| arr.drop(index) | 根据索引 删除数组arr的元素, 会生成新的数组 | 
| arr.update(index, newNum) 或者 arr(index) = newNum | 根据索引 修改数组arr的元素, 会生成新的数组 | 
| arr.reverse | 反转整个数组, 会生成新的数组 | 
不可变数组的遍历方法:1.普通遍历(增强for循环), for(i <- arr) print(i)
2.索引遍历(indices), for(i <- arr.indices) print(arr(i))
3.迭代器遍历(arr.iterator), val it = arr.iterator it.hasNext print(it.next)
4.使用mkString方法, print(arr.mkString()
5.使用foreach方法, arr.foreach((elem: Int) => {print(elem)}) 可化简为: arr.foreach(elem => print)
补充:
indices实际上是一个封装起来的函数:
 /** Produces the range of all indices of this sequence.
   *
   *  @return  a `Range` value from `0` to one less than the length of this $coll.
   */
  def indices: Range = 0 until length
[案例实操]
package ImMutableArrayDemo
object ArrayTest {
  def main(args: Array[String]): Unit = {
   //1. 创建不可变数组方式1
   //val arr:Array[Int] = new Array[Int](5)
    val arr = new Array[Int](5)
    //1. 创建不可变数组方式2
    val arr1 = Array(2,3,4,5,6)
    var arr3 = Array(2,3,false, "sbareu", 'a', 5.6)
    println(arr)
    //1.0 不可变数组- 访问某一元素, 直接索引访问
    println(arr(2) + ',' + arr(3))
    ///1.1 不可变数组-增加元素 (由于是不可变数组, 所以增加元素时, 生成了新的数组,
    //  可以看到地址值不相同)
    // :+ 向集合的尾部追加元素, +: 头部追加
    // ++ 连接前后两个集合 ::: 连接前后两个List
    // 注意:    :  冒号始终靠近集合变量这一端
    val ints:Array[Int] = arr :+ 88  //尾部追加
    val intsa:Array[Int] = 88 +: arr //头部追加
    val intsb = 77 +: 88 +: arr :+ 22 //连续追加
    var intsc: Array[Int] = arr ++ Array(2,3,4,2) //集合追加
    ///1.2 不可变数组-删除元素
    arr.update(2,8)
    println(ints.mkString(","))
    val ints1 = ints.drop(2)
    println(ints1.mkString(","))
    
    ///1.3 不可变数组-修改元素, 两种方式, 1. 索引直接修改, 2. 数组.update(index, num)
    arr(2) = 2
    arr.update(3,3)
    ///1.4 不可变数组-遍历元素
    //1.4.1 普通遍历
    for( i <- arr) print(i + ", ")
    println()
    / arr.indices 是返回数组的所有索引值!!,
    // 所以下面的for循环是遍历的索引值
    for( i <- arr.indices) print( arr(i) + ", ")
    println()
    /1.4.2 简化遍历(即增强for循环, for(容器内元素变量 <- 容器))
    //直接遍历所有元素, 不考虑索引
    for(elem <- arr) print(elem + ", ")
    println()
    /1.4.3 迭代器遍历
    val it = arr.iterator
    while(it.hasNext){
      print(it.next() + ", ")
    }
    println()
    /1.4.4 调用foreach方法遍历
    //   复习: Scala匿名函数写法 (参数列表) => {函数体}
    arr.foreach((elem: Int) => {print(elem + ", ")})
    //化简: arr.foreach(elem => print(elem + ", "))
    //再化简 arr.foreach(print)
    println()
    /1.4.5 遍历数组, 并添加连字符
    val str = arr.mkString("--")
    println(str)
    println("==========================================")
    for(i <- arr3){
      print(i + ", ")
    }
  }
}
补充: 为什么Scala中
Array(num)等同于new Array(num)?
5.2.2 可变数组
[基本语法]
var arrBuf = ArrayBufferAny
- [Any]存放任意数据类型;
- (1,2,3,4,5) 为初始化好的三个元素, 也可以把括号放空;
- ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer;
[常用增删改方法]
| 写法 | 解释 | 
|---|---|
| arrBuf(index) | 根据索引 访问可变数组arrBuf的元素, print(arrBuf)中, 默认会调用可变数组类ArrayBuffer的toString方法 | 
| arrBuf.append 或 += | 向集合的 尾部追加元素 | 
| arrBuf.prepend 或 +=: | 向集合的 头部追加元素,冒号始终靠近集合变量一端 | 
| arrBuf.insert(index, Any*) | 向集合的指定 索引处插入任意个元素 | 
| arrBuf.remove(index, count) 或 -= | 删除数组arr指定索引后的count个元素 | 
| arrBuf.update(index, newNum) 或者 arrBuf(index) = newNum | 根据索引 修改数组arr的元素 | 
[案例实操]
package mutableArraydemo
import scala.collection.mutable.ArrayBuffer
object MutableArrayTest {
  def main(args: Array[String]): Unit = {
    
    //可变数组的创建初始化
    //val arrBuf:ArrayBuffer[Int] = new ArrayBuffer[Int](5)
    val arrBuf = new ArrayBuffer[Int]()
    val arrBuf1 = ArrayBuffer[Any](1,3,5,7,8)
    //访问
    println(arrBuf1)   //隐式的调用了toString()
    print(arrBuf1(2))
    println()
    //向后追加元素  append +=
    //头部追加 prepend +=:
    arrBuf1.append(6,9,11)
    print(arrBuf1.mkString("-"))
    println()
    //插入元素  insert
    arrBuf1.insert(3,6)
    print(arrBuf1.mkString("-"))
    println()
    //修改元素  arr(index)    .update
    arrBuf1(1) = 2
    arrBuf1.update(0, 88)
    print(arrBuf1.mkString("-"))
    println()
    //删除元素 remove  -=
    arrBuf1.remove(0)
    arrBuf1 -= 11  //删除指定元素
    print(arrBuf1.mkString("-"))
    println()
    //反转元素 reverse
    print(arrBuf1.reverse.mkString("-"))
    println()
    //遍历集合(跟不可变数组的遍历方式完全一致)
    //1. mkString
    //2. for( i <- 集合)
    //3. iterator
    //4. 集合.indices  遍历索引
    //5. 集合.foreach(elem => print)
  }
}
5.2.3 不可变数组与可变数组的转换
[基本语法]
| 语法 | 解释 | 
|---|---|
| arr.toBuffer | 不可变数组转为可变数组(toBuffer), 返回的是一个可变数组, arr不会变化的噢! | 
| arr.toArray | 可变数组转为不可变数组(toArray), 返回的是一个不可变数组, arr不会变化的噢! | 
[案例实操]

5.2.4 多维数组
[基本语法]
val arr = Array.ofDim[T](一维数组的个数, 一维数组的元素数)
- 如: val arr = Array.ofDimDouble 
  - 说明:二维Double数组中(三行四列)有三个一维数组,每个一维数组中有四个元素
 
[案例实操]

- 几维数组几个foreach
5.3 列表List
- 列表是有序的, 可以包含重复项, 可变(List)或不可变(List)
- 没有索引的线性序列
5.3.1 不可变 List
[基本语法]
- 创建
val list: List[T] = List()
- 访问
1. 直接打印 print(list)
2. 索引访问 print(list(index))
[案例实操]
//定义一个list, 并访问
val list = List(1,2,3,4,5) //注意. List不存在new方式创建对象
print(list) //List中重写了toString(),可以直接打印
print(list(2)) //list(index), list可以通过索引访问
//创建一个空集合,Nil是一个独立的类,它继承于List[Nothing].
val nil: Nil.type = Nil
//打印Nil会打印List()
println(nil)
5.3.1.1 头,尾追加元素(:+ :+)
- 借助
+:,:+, 可以向List中添加元素
由于 List 本身是不可改变的,因此追加操作不会改变原来的 List ,而是返回一个新的 List。Scala 的 List 提供操作符号来表示追加,比如头插入 +: 和尾部追加 :+
 `
//在列表后面追加元素,使用函数 :+ ,且 list 写在前面。
val addTohead: List[Int] = list :+ 0
//在列表前面追加元素,使用函数 +: ,且 list 写在后面。
val addToTail: List[Int] = 6 +: list
5.3.1.2 拼接List ::
 
- 借助
::来整体拼接多个List(List会被当做是一个整体)
除了头部插入,尾部插入之外,使用 :: 符号可以实现将多个零散的元素拼接到 List 当中。

5.3.1.2 扁平化拼接List :::
 

扁平化(flat): 讲一个整体拆成一个一个的个体, 称为扁平化;
5.3.2 可变 ListBuffer


5.4 集合 Set
- 集合无序, 不可以包含重复项
- Scala中的Set同样分为可变(mutable)和 不可变(immutable)的, 默认情况下是不可变的;
//创建一个不可变的Set集合。
val immutableInts = Set(1,2,3,4)
//创建一个可变的Set集合。
val mutableInts = mutable.Set(1,2,3,4,5)
5.4.1 向Set中添加元素

5.4.2 移除Set内的元素

5.4.3 Set集合的常用方法

5.5 集合 Map
- 与Java的Map类似, 散列表, 存储内容为键值对
- 可变Map无序,- 不可变Map有序,- 键key均不可重复

不可变 Map的常见操作
package mapdemo
object ImutableDemo {
  //不可变Map
  def main(args: Array[String]): Unit = {
    val map: Map[String, Int] = Map("xiaoming" -> 18, ("xiaowang", 22), "xiaogou" -> 30)
    //访问数据,
    //1. 获取key, map.keys, 通过key获取值
    for(key <- map.keys){
      println(s"key: ${key}, value: ${map.get(key)}" )
    }
    //Q: 为什么上面的遍历返回了Some?
    //1.1. get(key),如果遇到value无值在呢么办?
    val maybeInt: Option[Int] = map.get("xiaowu")
    println(maybeInt)
    //Q: Option是什么?
     //1.2. getOrElse
    println(map.getOrElse("xiaoliu", -1))
    //2. 遍历map
    map.foreach((kv) => {println(kv)})
    println("========")
    //3. map 添加新的键值对, map + ((k1, v1), (k2, v2)), 会生成新的map对象
    val map2 = map.+(("xiaozhou", 27))
    //4. map删除键值对, 会生成新的map对象
    val map3 = map2.-("xiaogou")
    map3.foreach((kv) => {println(kv)})
  }
}
可变Map的常见操作
package mapdemo
import scala.collection.mutable
object MutableMapDemo {
  def main(args: Array[String]): Unit = {
    //1. 创建可变的map对象
    val map: mutable.Map[String, Int] = mutable.Map("xiaogou" -> 26, ("xiaosan", 13), ("xiaochen", 18))
    //2. 获取key,   map.keys
    for (key <- map.keys) {
      println(s"KEY: ${key}, VALUE: ${map.get(key)}")
    }
    //  map.getOrElse
    println(s"KEY: asd, VALUE: ${map.getOrElse("asd", "no data")}")
    //3. 可变map增加键值对    += 或 put(key, value)
    val map1: mutable.Map[String, Int] = map + (("xiaosi", 28))
    map1.foreach((kv) => print(kv + "; "))
    println()
    map += ("xiaoming" -> 35)
    map.put("wangwu", 35)
    map.foreach((kv) => print(kv + "; "))
    //4. 可变Map删除指定键值对 -=
    println()
    map -= ("xiaogou")
    map.foreach((kv) => print(kv + "; "))
    //5. 可变map修改指定key的值  update() 或 直接赋值 map(key) = newValue
    println()
    map.update("wangwu", 48)
    map.foreach((kv) => print(kv + "; "))
  }
}
5.5.2 根据Key取出Map内的value

5.5.3 使用 contains 方法检查 key 是否存在

5.5.4 使用 get 方法避免异常

5.5.5 简洁的 getOrElse 方法

5.5.6 如何选择这几种取值方式

5.5.7 对Map的增删改查
- 见上方代码示例, 待凝练
5.5.8 对Map的遍历

5.6 元组 Tuple
- 在不使用类的情况下, 将元素组合起来形成简单的逻辑集合;
- 查看文章: 五-1, Scala 元组(Tuple)
5.8 队列 Queue
- 待补充
参考文章:
- Scala 编程
- scala 集合
 
                    
                

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号