概述
Scala 集合框架提供了多种集合类型,包括:
- 列表(List):不可变链表,支持快速在头部进行插入和删除操作,但不提供快速按下标进行访问。
- 数组(Array):支持快速按索引进行访问,但插入和删除操作会涉及数组的扩容和移动操作,效率较低。
- 列表缓冲(ListBuffer):ListBuffer 是一个可变的链表,可以在列表尾部高效地追加元素时,在构建完列表缓冲之后,可以使用
toList
方法将其转换为不可变列表。 - 数组缓冲(ArrayBuffer):数组缓冲与数组类似。
- 元组(Tuple):元组是一种不可变的数据结构,可以通过索引访问其中的元素,但无法修改元组中的元素。
Scala 集合类库同时提供了可变和不可变两个版本的集合和映射。当我们使用 Set
和 Map
时,默认得到的是一个不可变的对象,如果想使用可变版本,则需要显式进行引入。
列表基本操作
创建列表
所有的列表都构建自两个基础的构建单元 Nil
和 ::
(读作“cons”),Nil
用于表示空列表,中缀操作符 ::
用于在列表前追加元素。
1val fruit = "apples" :: ("oranges" :: ("pears" :: Nil))
2val nums = 1 :: (2 :: (3 :: (4 :: Nil)))
3
4println(fruit) // List(apples, oranges, pears)
5println(nums) // List(1, 2, 3, 4)
由于操作符::
以 :
结尾,所以它是右结合的,因此我们可以省略定义中的圆括号,例如:
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2
3println(nums) // List(1, 2, 3, 4)
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2
3// 判断列表是否为空
4println(nums.isEmpty) // false
5
6// 获取列表的长度
7println(nums.length) // 4
列表元素选择
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2
3// 打印列表中的第一个元素
4println(nums.head) // 1
5
6// 打印列表中的最后一个元素
7println(nums.last) // 4
8
9// 打印列表中除第一个元素之外的所有元素构成的列表
10println(nums.tail) // List(2, 3, 4)
11
12// 打印列表中除最后一个元素之外的所有元素构成的列表
13println(nums.init) // List(1, 2, 3)
apply(n: Int)
方法表示获取列表中索引为 n
的元素。
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2println(nums(1)) // 2
3println(nums.apply(2)) // 3
drop
方法和 take
方法分别是对 head
方法和 tail
方法的一般化:
- 表达式
list.drop(n)
表示从list
中删除前n
个元素,如果n
大于list.length
,则返回一个空列表。 - 表达式
list.take(n)
表示从list
中取出前n
个元素,如果n
大于list.length
,则返回list
本身。
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2println(nums.drop(2)) // List(3, 4)
3println(nums.take(2)) // List(1, 2)
获取列表中元素的索引构成的列表:
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2println(nums.indices)
3for (i <- nums.indices) {
4 println(s"nums[$i] = ${nums(i)}")
5}
6// Expected output:
7// Range 0 until 4
8// nums[0] = 1
9// nums[1] = 2
10// nums[2] = 3
11// nums[3] = 4
列表切分
splitAt(n: Int)
方法表示将列表分成两个部分,第一个部分包含前 n
个元素,第二个部分包含剩余的元素。
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2val (nums1, nums2) = nums.splitAt(2)
3println(nums1) // List(1, 2)
4println(nums2) // List(3, 4)
列表拼接
:::
操作符用于拼接两个列表,:::
是右结合的,也就是说 a ::: b ::: c
等价于 a ::: (b ::: c)
:
1val nums1 = 1 :: 2 :: 3 :: Nil
2val nums2 = 4 :: 5 :: 6 :: Nil
3val nums = nums1 ::: nums2
4println(nums) // List(1, 2, 3, 4, 5, 6)
列表翻转
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2
3// 翻转列表
4println(nums.reverse) // List(4, 3, 2, 1)
列表扁平化
flatten
方法接收一个列表的列表并将它扁平化,返回单个列表,示例如下:
1val list= List(List(1, 2), List(3), List(), List(4, 5)).flatten
2println(list) // List(1, 2, 3, 4, 5)
模式匹配解包
1val fruit = "apples" :: "oranges" :: "pears" :: Nil
2
3val List(a, b, c) = fruit
4println(a) // apples
5println(b) // oranges
6println(c) // pears
7
8val d :: e :: rest = fruit
9println(d) // apples
10println(e) // oranges
11println(rest) // List(pears)
转换为字符串
toSting
方法和 mkString
方法用于将列表转换成字符串。
1val nums = 1 :: 2 :: 3 :: 4 :: Nil
2println(nums.toString) // List(1, 2, 3, 4)
3println(nums.mkString(", ")) // 1, 2, 3, 4
转换为数组
列表的 toArray
方法用于将列表转换为数组:
1val list = 1 :: 2 :: 3 :: 4 :: Nil
2val array = list.toArray
3println(array.mkString(", ")) // 1, 2, 3, 4
数组的 toList
方法用于将数组转换为列表:
1val array = Array(1, 2, 3, 4)
2val list = array.toList
3println(list) // List(1, 2, 3, 4)
列表的 copyToArray(xs, start)
方法用于将列表复制到数组 xs
中下标 start
开始的位置:
1val list = 1 :: 2 :: 3 :: 4 :: Nil
2val array = Array.ofDim[Int](10)
3list.copyToArray(array, 5)
4println(array.mkString(", ")) // 0, 0, 0, 0, 0, 1, 2, 3, 4, 0
List 伴生对象
List 伴生对象的 apply
方法用于创建一个列表,empty
方法用于创建一个空列表。
1// 创建一个空列表
2println(List.apply()) // List()
3
4// 创建一个包含指定元素的列表
5println(List.apply(1, 2, 3, 4)) // List(1, 2, 3, 4)
6
7// 创建一个包含区间数值的列表
8println(List.range(1, 9, 2)) // List(1, 3, 5, 7)
9println(List.range(9, 1, -3)) // List(9, 6, 3)
ListBuffer 基本操作
1import scala.collection.mutable.ListBuffer
2
3object Main extends App {
4 var listBuffer = new ListBuffer[Int]()
5
6 // 在尾部追加一个元素 3
7 listBuffer += 3 // ListBuffer(3)
8
9 // 在尾部追加一个元素 4
10 listBuffer += 4 // ListBuffer(3, 4)
11
12 // 在头部追加一个元素 2
13 2 +=: listBuffer // ListBuffer(2, 3, 4)
14
15 // 在头部插入一个元素 1
16 1 +=: listBuffer // ListBuffer(1, 2, 3, 4)
17
18 // 将 ListBuffer 转换为 List
19 println(listBuffer.toList) // List(1, 2, 3, 4)
20}
ArrayBuffer 基本操作
1import scala.collection.mutable.ArrayBuffer
2
3object Main extends App {
4 var arrayBuffer = new ArrayBuffer[Int]()
5
6 // 在尾部追加一个元素 3
7 arrayBuffer += 3 // ArrayBuffer(3)
8
9 // 在尾部追加一个元素 4
10 arrayBuffer += 4 // ArrayBuffer(3, 4)
11
12 // 在头部追加一个元素 2
13 2 +=: arrayBuffer // ArrayBuffer(2, 3, 4)
14
15 // 在头部插入一个元素 1
16 1 +=: arrayBuffer // ArrayBuffer(1, 2, 3, 4)
17
18 // 将 ArrayBuffer 转换为 List
19 println(arrayBuffer.toList) // List(1, 2, 3, 4)
20
21 // 将 ArrayBuffer 转换为 Array
22 println(arrayBuffer.toArray.mkString(", ")) // 1, 2, 3, 4
23
24}
元组基本操作
元组(Tuple)相比于列表和数组来说,它的元素是异构的,也就是说元组的元素可以是不同类型的。
要访问元组的元素,可以使用 _1
访问第一个元素、使用 _2
访问第二个元素,以此类推。
1// 创建一个元组
2val tuple = ("scala", 1024, 3.14, List(1, 2, 3))
3
4// 打印元组的第一个元素
5println(tuple._1) // scala
6
7// 打印元组的第二个元素
8println(tuple._2) // 1024
9
10// 打印元组的第三个元素
11println(tuple._3) // 3.14
12
13// 打印元组的第四个元素
14println(tuple._4) // List(1, 2, 3)
可以在一条赋值语句中将元组的元素赋值给多个变量,例如:
1val tuple = ("scala", 1024, 3.14, List(1, 2, 3))
2val (s, i, d, l) = tuple
3println(s) // scala
4println(i) // 1024
5println(d) // 3.14
6println(l) // List(1, 2, 3)
注意,上述赋值语句左侧中的圆括号 ()
不能省略,省略则表示左侧所有变量都通过右侧的表达式进行初始化:
1val tuple = ("scala", 1024, 3.14, List(1, 2, 3))
2val s, i, d, l = tuple
3println(s) // (scala,1024,3.14,List(1, 2, 3))
4println(i) // (scala,1024,3.14,List(1, 2, 3))
5println(d) // (scala,1024,3.14,List(1, 2, 3))
6println(l) // (scala,1024,3.14,List(1, 2, 3))
可以使用占位符 _
来忽略元组中的某些元素,例如:
1val tuple = ("scala", 1024, 3.14, List(1, 2, 3))
2val (s, i, _, _) = tuple
3println(s) // scala
4println(i) // 1024
总结
- Scala 集合框架提供了不可变和可变两个版本,默认使用不可变的集合框架。如果需要使用可变版本,则需要手动从
scala.collection.immutable
包中导入。