0%

scala集合

Scala 集合:不可变与可变的完美融合

Scala 集合框架是处理数据集合的核心工具,其设计兼顾了不可变性(线程安全、函数式编程友好)和可变性(性能优化、状态修改),提供了丰富的数据结构(序列、集合、映射等)和操作方法。本文将系统解析 Scala 集合的层级结构、核心类型及常用操作,帮助你高效处理各类数据集合。

集合框架概览

Scala 集合分为两大体系:不可变集合(默认)和可变集合,分别位于不同的包中:

  • 不可变集合scala.collection.immutable,集合创建后无法修改,所有操作返回新集合。

    不可变集合

  • 可变集合scala.collection.mutable,集合可直接修改,操作效率更高。

    可变集合层级关系

核心特质与继承关系

所有集合都扩展自 Iterable 特质,主要分为三大类:

  1. Seq(序列):有序集合(如数组、列表、队列),元素按顺序访问,可通过索引访问。
  2. Set(集合):无序集合,元素唯一,无重复值。
  3. Map(映射):键值对集合,键唯一,值可重复。

序列(Seq)

序列是有序集合,支持索引访问,核心类型包括数组(Array)、变长数组(ArrayBuffer)、列表(List)、队列(Queue)等。

定长数组(Array)

与 Java 数组类似,长度固定,初始化后不可修改,支持泛型。

定义方式
1
2
3
4
5
6
7
// 方式1:指定长度和类型(默认值为0、null等)
val arr1 = new Array[Int](5) // 长度为5的Int数组,默认值0
val arr2 = new Array[String](3) // 长度为3的String数组,默认值null

// 方式2:直接初始化元素(调用apply方法)
val arr3 = Array(1, 2, 3, 4) // Int数组:Array(1, 2, 3, 4)
val arr4 = Array("a", "b", "c") // String数组:Array(a, b, c)
常用操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
val arr = Array(10, 20, 30)

// 访问元素(索引从0开始)
println(arr(0)) // 输出:10

// 修改元素
arr(1) = 200
println(arr(1)) // 输出:200

// 长度
println(arr.length) // 输出:3

// 遍历
for (num <- arr) println(num)

变长数组(ArrayBuffer)

类似 Java 的 ArrayList,长度可动态变化,适合频繁添加 / 删除元素的场景(需导入 scala.collection.mutable.ArrayBuffer)。

定义与操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import scala.collection.mutable.ArrayBuffer

// 初始化空数组
val buf = ArrayBuffer[Int]()

// 添加元素
buf += 10 // 追加单个元素
buf += (20, 30) // 追加多个元素
buf ++= Array(40, 50) // 追加数组

// 修改元素
buf(0) = 100

// 删除元素
buf.remove(1) // 删除索引1的元素
buf -= 30 // 删除值为30的元素

// 转换为定长数组
val arr = buf.toArray

// 遍历
buf.foreach(println) // 输出:100, 40, 50

列表(List)

不可变序列,元素按链表结构存储,适合头插操作(效率高),尾插操作效率低。

定义与操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 初始化列表
val list1 = List(1, 2, 3) // List(1, 2, 3)
val emptyList = Nil // 空列表:List()

// 头部添加元素(:: 操作符,右结合)
val list2 = 0 :: list1 // List(0, 1, 2, 3)
val list3 = 4 :: 5 :: Nil // List(4, 5)

// 尾部添加元素(效率低,需遍历整个列表)
val list4 = list1 :+ 6 // List(1, 2, 3, 6)

// 列表拼接(::: 拼接两个列表)
val list5 = list2 ::: list3 // List(0, 1, 2, 3, 4, 5)

// 访问元素(索引从0开始)
println(list5(2)) // 输出:2

// 常用方法
println(list5.head) // 首元素:0
println(list5.tail) // 除首元素外的子列表:List(1, 2, 3, 4, 5)
println(list5.isEmpty) // 是否为空:false

可变列表(ListBuffer)

可变版本的 List,支持高效的头部和尾部操作(需导入 scala.collection.mutable.ListBuffer)。

定义与操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import scala.collection.mutable.ListBuffer

val lb = ListBuffer(1, 2, 3)

// 添加元素
lb += 4 // 尾插
lb.+=:(0) // 头插(等价于 0 +: lb)
lb.insert(2, 100) // 在索引2插入100

// 删除元素
lb.remove(3) // 删除索引3的元素
lb -= 4 // 删除值为4的元素

// 遍历
lb.foreach(println) // 输出:0, 1, 100, 3

队列(Queue)

遵循先进先出(FIFO) 原则的有序集合,分为不可变和可变版本(常用可变队列,需导入 scala.collection.mutable.Queue)。

定义与操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import scala.collection.mutable.Queue

val queue = Queue(1, 2, 3)

// 入队(添加到尾部)
queue.enqueue(4)
queue += 5

// 出队(移除并返回头部元素)
val head = queue.dequeue() // head = 1,队列变为 Queue(2, 3, 4, 5)

// 访问元素(不修改队列)
println(queue.head) // 头部:2
println(queue.last) // 尾部:5
println(queue.tail) // 除头部外的子队列:Queue(3, 4, 5)

元组(Tuple)

元组用于存储不同类型的元素(最多 22 个),是将多个值封装为单一对象的轻量结构。

定义与操作

1
2
3
4
5
6
7
8
9
10
11
12
13
// 定义元组(元素类型可不同)
val tuple = (1, "scala", 3.14, true) // Tuple4[Int, String, Double, Boolean]

// 访问元素(索引从1开始,使用 _N 语法)
println(tuple._1) // 1
println(tuple._2) // "scala"

// 遍历(通过 productIterator)
tuple.productIterator.foreach(println) // 依次输出:1, scala, 3.14, true

// 模式匹配提取元素
val (a, b, c, d) = tuple
println(s"a=$a, b=$b") // a=1, b=scala

集合(Set)

Set 是无序且元素唯一的集合,分为不可变和可变版本(默认不可变)。

不可变 Set

1
2
3
4
5
6
7
8
9
10
11
12
13
// 初始化(自动去重)
val set1 = Set(1, 2, 2, 3) // Set(1, 2, 3)

// 添加元素(返回新集合)
val set2 = set1 + 4 // Set(1, 2, 3, 4)

// 删除元素(返回新集合)
val set3 = set2 - 2 // Set(1, 3, 4)

// 集合运算
val set4 = Set(3, 4, 5)
println(set3 & set4) // 交集:Set(3, 4)
println(set3 ++ set4) // 并集:Set(1, 3, 4, 5)

可变 Set

需导入 scala.collection.mutable.Set,支持直接修改集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import scala.collection.mutable.Set

val set = Set(1, 2, 3)

// 添加元素
set += 4
set.add(5)

// 删除元素
set -= 2
set.remove(3)

// 遍历
set.foreach(println) // 输出:1, 4, 5(顺序不固定)

映射(Map)

Map 是键值对(key-value) 集合,键唯一,值可重复,分为不可变和可变版本(默认不可变)。

不可变 Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 初始化(键值对用 -> 或元组表示)
val map1 = Map("name" -> "Alice", "age" -> 20)
val map2 = Map(("id", 1), ("score", 90))

// 访问值(get 方法返回 Option,避免空指针)
println(map1.get("name")) // Some(Alice)
println(map1.getOrElse("gender", "unknown")) // unknown(键不存在时返回默认值)

// 添加/修改键值对(返回新 Map)
val map3 = map1 + ("age" -> 21) // 修改 age 的值
val map4 = map3 + ("gender" -> "female") // 添加新键值对

// 删除键(返回新 Map)
val map5 = map4 - "score"

可变 Map

需导入 scala.collection.mutable.Map,支持直接修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import scala.collection.mutable.Map

val map = Map("name" -> "Bob", "age" -> 25)

// 添加/修改键值对
map("age") = 26 // 修改
map += ("gender" -> "male") // 添加
map.put("id", 2) // 添加

// 删除键
map -= "name"
map.remove("id")

// 遍历
map.foreach { case (k, v) => println(s"$k: $v") }
// 输出:
// age: 26
// gender: male

集合的通用操作

所有 Scala 集合都支持一系列通用方法,简化数据处理:

方法 功能描述 示例(以 List (1,2,3) 为例)
head 返回首元素 list.head → 1
tail 返回除首元素外的子集合 list.tail → List(2, 3)
isEmpty 判断是否为空 list.isEmpty → false
nonEmpty 判断是否非空 list.nonEmpty → true
size 返回元素个数 list.size → 3
contains(x) 判断是否包含元素 x list.contains(2) → true
filter(f) 过滤出满足条件 f 的元素 list.filter(_ > 1) → List(2, 3)
map(f) 对每个元素应用函数 f 并返回新集合 list.map(_ * 2) → List(2, 4, 6)
flatMap(f) 对每个元素应用函数 f(返回集合)并扁平化 list.flatMap(x => List(x, x)) → List(1,1,2,2,3,3)
foldLeft(z)(f) 从左到右折叠,以 z 为初始值应用函数 f list.foldLeft(0)(_ + _) → 6
foreach(f) 对每个元素执行函数 f(无返回值) list.foreach(println) → 打印 1,2,3

不可变与可变集合的选择

  • 优先使用不可变集合
    • 线程安全,适合并发场景。
    • 函数式编程风格(无副作用)。
    • 避免意外修改导致的 bug。
  • 使用可变集合的场景
    • 频繁修改集合(如循环中添加元素),性能更优。
    • 需要共享状态并修改(如缓存、计数器)。

欢迎关注我的其它发布渠道