Seq 特征表示序列。序列是一种可迭代对象,它具有length
,并且其元素具有从0
开始的固定索引位置。
序列上的操作(总结在下表中)分为以下几类
- 索引和长度操作
apply
、isDefinedAt
、length
、indices
和lengthCompare
。对于Seq
,apply
操作表示索引;因此,类型为Seq[T]
的序列是一个偏函数,它采用Int
参数(一个索引),并生成类型为T
的序列元素。换句话说,Seq[T]
扩展了PartialFunction[Int, T]
。序列的元素从零开始索引,直到序列的length
减一。序列上的length
方法是一般集合的size
方法的别名。lengthCompare
方法允许您将序列的长度与 Int 或Iterable
进行比较,即使序列具有无限长度。 - 索引搜索操作
indexOf
、lastIndexOf
、indexOfSlice
、lastIndexOfSlice
、indexWhere
、lastIndexWhere
、segmentLength
,它们返回等于给定值或匹配某个谓词的元素的索引。 - 加法操作
prepended
、prependedAll
、appended
、appendedAll
、padTo
,它们返回通过在序列的前面或末尾添加元素而获得的新序列。 - 更新操作
updated
、patch
,它们返回通过替换原始序列中的一些元素而获得的新序列。 - 排序操作
sorted
、sortWith
、sortBy
,它们根据各种标准对序列元素进行排序。 - 反转操作
reverse
、reverseIterator
,它们生成或处理反向顺序的序列元素。 - 比较
startsWith
、endsWith
、contains
、containsSlice
、corresponds
、search
,它们关联两个序列或在序列中搜索元素。 - 多重集 操作
intersect
、diff
、distinct
、distinctBy
,它们对两个序列的元素执行类似集合的操作或移除重复项。
如果序列是可变的,它还提供一个副作用 update
方法,它允许更新序列元素。与 Scala 中一贯的做法一样,seq(idx) = elem
这样的语法只是 seq.update(idx, elem)
的简写,因此 update
免费提供了方便的赋值语法。请注意 update
和 updated
之间的区别。update
就地更改序列元素,并且仅适用于可变序列。updated
适用于所有序列,并且始终返回一个新序列,而不是修改原始序列。
Seq 类中的操作
它是什么 | 它做什么 |
---|---|
索引和长度 | |
xs(i) |
(或写成 xs.apply(i) )。xs 在索引 i 处的元素。 |
xs.isDefinedAt(i) |
测试 i 是否包含在 xs.indices 中。 |
xs.length |
序列的长度(与 size 相同)。 |
xs.lengthCompare(n) |
如果 xs 短于 n ,则返回 -1 ,如果它更长,则返回 +1 ,如果它的长度为 n ,则返回 0 。即使序列是无限的,此方法也能正常工作,例如 LazyList.from(1).lengthCompare(42) 返回一个正值。 |
xs.indices |
索引范围 xs ,从 0 扩展到 xs.length - 1 。 |
索引搜索 | |
xs.indexOf(x) |
在 xs 中第一个等于 x 的元素的索引(存在多个变体)。 |
xs.lastIndexOf(x) |
在 xs 中最后一个等于 x 的元素的索引(存在多个变体)。 |
xs.indexOfSlice(ys) |
第一个索引 xs ,从该索引开始的连续元素形成序列 ys 。 |
xs.lastIndexOfSlice(ys) |
最后一个索引 xs ,从该索引开始的连续元素形成序列 ys 。 |
xs.indexWhere(p) |
xs 中第一个满足 p 的元素的索引(存在多个变体)。 |
xs.segmentLength(p, i) |
元素的最长不间断段的长度 xs ,从 xs(i) 开始,所有这些元素都满足谓词 p 。 |
添加 | |
xs.prepended(x) 或 x +: xs |
一个新的序列,其中包含 x 前置于 xs 。 |
xs.prependedAll(ys) 或 ys ++: xs |
一个新的序列,其中包含 ys 的所有元素前置于 xs 。 |
xs.appended(x) 或 xs :+ x |
一个新的序列,其中包含 x 附加于 xs 。 |
xs.appendedAll(ys) 或 xs :++ ys |
一个新序列,由所有元素 ys 附加到 xs 组成。 |
xs.padTo(len, x) |
通过将值 x 附加到 xs ,直到达到长度 len ,得到的结果序列。 |
更新 | |
xs.patch(i, ys, r) |
通过用修补程序 ys 替换从 i 开始的 xs 的 r 个元素,得到的结果序列。 |
xs.updated(i, x) |
一个 xs 的副本,其中索引 i 处的元素被 x 替换。 |
xs(i) = x |
(或者写成 xs.update(i, x) ,仅适用于 mutable.Seq )。将 xs 在索引 i 处的元素更改为 x 。 |
排序 | |
xs.sorted |
通过使用 xs 的元素类型的标准顺序对 xs 的元素进行排序而获得的一个新序列。 |
xs.sortWith(lt) |
通过使用 lt 作为比较操作对 xs 的元素进行排序而获得的一个新序列。 |
xs.sortBy(f) |
通过对 xs 的元素进行排序而获得的一个新序列。对两个元素之间的比较通过对这两个元素映射函数 f 并比较结果来进行。 |
反转 | |
xs.reverse |
一个序列,其中包含 xs 的元素,但顺序相反。 |
xs.reverseIterator |
一个迭代器,生成 xs 的所有元素,但顺序相反。 |
比较 | |
xs.sameElements(ys) |
一个测试,用于判断 xs 和 ys 是否包含相同的元素,顺序也相同 |
xs.startsWith(ys) |
测试 xs 是否以序列 ys 开头(有多种变体)。 |
xs.endsWith(ys) |
测试 xs 是否以序列 ys 结尾(有几种变体)。 |
xs.contains(x) |
测试 xs 是否具有等于 x 的元素。 |
xs.search(x) |
测试已排序序列 xs 是否具有等于 x 的元素,可能比 xs.contains(x) 更有效率。 |
xs.containsSlice(ys) |
测试 xs 是否具有等于 ys 的连续子序列。 |
xs.corresponds(ys)(p) |
测试 xs 和 ys 的对应元素是否满足二元谓词 p 。 |
多重集操作 | |
xs.intersect(ys) |
序列 xs 和 ys 的多重集交集,保留 xs 中元素的顺序。 |
xs.diff(ys) |
序列 xs 和 ys 的多重集差集,保留 xs 中元素的顺序。 |
xs.distinct |
不包含重复元素的 xs 子序列。 |
xs.distinctBy(f) |
在应用转换函数 f 后不包含重复元素的 xs 子序列。例如,List("foo", "bar", "quux").distinctBy(_.length) == List("foo", "quux") |
特性 Seq 有两个子特性 LinearSeq 和 IndexedSeq。这些特性不会为不可变分支添加任何新操作,但每个特性都提供不同的性能特征:线性序列具有高效的 head
和 tail
操作,而索引序列具有高效的 apply
、length
以及(如果可变)update
操作。常用的线性序列是 scala.collection.immutable.List
和 scala.collection.immutable.LazyList
。常用的索引序列是 scala.Array
和 scala.collection.mutable.ArrayBuffer
。 Vector
类在索引访问和线性访问之间提供了一个有趣的折衷方案。它既具有有效恒定时间索引开销,又具有恒定时间线性访问开销。因此,向量是混合访问模式(同时使用索引访问和线性访问)的良好基础。您将在 后面 了解有关向量的更多信息。
在可变分支上,IndexedSeq
添加了用于就地转换其元素的操作(与 map
和 sort
等转换操作相反,这些操作在根 Seq
上可用,并返回一个新集合实例)。
可变的 IndexedSeq 类中的操作
它是什么 | 它做什么 |
---|---|
转换 | |
xs.mapInPlace(f) |
通过将 f 函数应用于 xs 的每个元素,转换 xs 的所有元素。 |
xs.sortInPlace() |
对集合 xs 进行排序。 |
xs.sortInPlaceWith(c) |
根据给定的比较函数 c 对集合 xs 进行排序。 |
xs.sortInPlaceBy(f) |
根据对函数 f 应用于每个元素的结果定义的顺序,对集合 xs 进行排序。 |
缓冲区
可变序列的一个重要子类别是 Buffer
。它们不仅允许更新现有元素,还允许添加、插入和移除元素。缓冲区支持的主要新方法有 append
和 appendAll
,用于在末尾添加元素;prepend
和 prependAll
,用于在开头添加元素;insert
和 insertAll
,用于插入元素;以及 remove
、subtractOne
和 subtractAll
,用于移除元素。下表总结了这些操作。
缓冲区的两个常用实现是 ListBuffer
和 ArrayBuffer
。顾名思义,ListBuffer
由 List
支持,并支持有效地将其元素转换为 List
,而 ArrayBuffer
由数组支持,并且可以快速转换为数组。
Buffer 类中的操作
它是什么 | 它做什么 |
---|---|
添加 | |
buf.append(x) 或 buf += x |
将元素 x 追加到缓冲区,并返回 buf 本身作为结果。 |
buf.appendAll(xs) 或 buf ++= xs |
将 xs 中的所有元素追加到缓冲区。 |
buf.prepend(x) 或 x +=: buf |
将元素 x 预置到缓冲区。 |
buf.prependAll(xs) 或 xs ++=: buf |
将 xs 中的所有元素预置到缓冲区。 |
buf.insert(i, x) |
在缓冲区的索引 i 处插入元素 x 。 |
buf.insertAll(i, xs) |
在缓冲区的索引 i 处插入 xs 中的所有元素。 |
buf.padToInPlace(n, x) |
将元素 x 追加到缓冲区,直到缓冲区中共有 n 个元素。 |
删除 | |
buf.subtractOne(x) 或 buf -= x |
从缓冲区中删除元素 x 。 |
buf.subtractAll(xs) 或 buf --= xs |
从缓冲区中删除 xs 中的元素。 |
buf.remove(i) |
从缓冲区中删除索引 i 处的元素。 |
buf.remove(i, n) |
从缓冲区中删除从索引 i 开始的 n 个元素。 |
buf.trimStart(n) |
从缓冲区中删除前 n 个元素。 |
buf.trimEnd(n) |
从缓冲区中删除后 n 个元素。 |
buf.clear() |
从缓冲区中删除所有元素。 |
替换 | |
buf.patchInPlace(i, xs, n) |
用 xs 中的元素替换缓冲区的(最多)n 个元素,从缓冲区中的索引 i 开始。 |
克隆 | |
buf.clone() |
一个与 buf 具有相同元素的新缓冲区。 |