List 相关操作
List
是 Kotlin 内建集合中最常用的类型. 基于下标的元素访问, 为 list 提供了很多功能强大的操作.
使用下标获取元素
List 支持所有集合共通的元素获取操作: elementAt()
, first()
, last()
, 以及在 获取集合的单个元素 中介绍的其他操作. List 独有的功能是使用下标访问元素, 因此读取一个元素的最简单方法是使用下标来访问它. 这个功能通过 get()
函数实现, 参数是元素下标, 或者也可以使用更简短的 [index]
语法.
如果 list 大小小于指定的下标, 会抛出一个异常. 另外两个其他函数, 可以避免这类异常:
getOrElse()
允许指定一个函数, 如果下标在集合中不存在, 可以通过这个函数来计算一个默认值.getOrNull()
返回null
作为下标不存在时的默认值.
获取 list 的一部分
除了 获取集合的一部分 中介绍过的共通操作之外, list 还提供了一个 subList()
函数, 它返回 list 中某个指定的下标范围中的元素构成的视图(view). 因此, 如果原集合中的元素发生变化, 那么在之前创建的子列表中它也会变化, 反过来也是如此.
查找元素位置
线性查找(Linear search)
对任何 list, 你可以使用 indexOf()
和 lastIndexOf()
函数查找一个元素的位置. 这些函数返回 list 中第一个和最后一个与参数相等的元素的位置. 如果不存在匹配的元素, 这两个函数都返回 -1
.
还有另一组函数, 接收的参数是一个判定条件, 并查找满足判定条件的元素:
indexOfFirst()
返回满足判定条件的 第一个元素的下标, 如果不存在匹配的元素, 则返回-1
.indexOfLast()
返回满足判定条件的 最后一个元素的下标, 如果不存在匹配的元素, 则返回-1
.
在排序的 list 中折半查找(Binary search)
在 list 中查找元素还有另一种方式 – 折半查找(binary search). 这种方法的速度要比其他内建函数快很多, 但它 要求 list 按照升序 排序, 排序方法可以是: 自然顺序, 或通过函数参数指定的其它顺序. 否则, 这个函数的查找结果是不确定的.
要在排序的 list 中查找一个元素, 请使用 binarySearch()
函数, 要查找的元素作为参数. 如果这个元素存在, 这个函数返回它的下标; 否则, 它返回 (-insertionPoint - 1)
, 其中的 insertionPoint
是为了保持 list 正确排序, 这个元素应该插入的下标. 如果存在多个元素等于指定的值, 查找结果可能返回其中任何一个的下标.
也可以指定查找的下标范围: 这种情况下, 这个函数只在指定的两个下标之间进行查找.
使用比较器(Comparator)进行折半查找(Binary search)
如果 list 元素不是 Comparable
对象, 那么在进行折半查找(Binary search)时, 需要提供一个 Comparator
. list 中的元素必须按这个 Comparator
比较的结果升序排列. 下面我们来看看示例程序:
这里我们有一个 Product
的 list, 其中的 Product
对象不是 Comparable
, 然后我们通过一个 Comparator
定义了它们的排序方式: 如果 p1
的价格低于 p2
, 则产品 p1
排在 p2
之前. 因此, 首先让 list 按照这个规则升序排列, 然后我们使用 binarySearch()
来查找指定的 Product
的下标.
如果 list 中的元素是 Comparable
对象, 但不使用其自然顺序, 比如, 对 String
不区分大小写排序的情况, 这时自定义的比较器也是很方便的.
使用比较(Comparison)函数进行折半查找(Binary search)
进行折半查找(Binary search)时, 使用 比较(Comparison) 函数, 不必指定确切的查找值即可查找元素. 这种查找方法不需要具体的元素值, 而是接受一个比较函数, 比较函数负责将元素变换为 Int
值, 然后查找变换结果为 0 的元素. list 必须按照比较函数规定的升序排序; 也就是说, list 中各个元素传递给比较函数之后的返回值必须是递增的.
使用比较器(Comparator)和比较(Comparison)函数的折半查找, 也同样可以针对 list 的下标范围进行查找.
List 的写入操作
除了 集合写入操作 中介绍的集合共通的写操作之外, 可变(mutable) list 还支持 list 独有的写操作. 这类操作使用下标访问元素的方式进行, 增加了 list 的修改能力.
添加元素
要将元素添加到 list 的指定位置, 可以使用 add()
和 addAll()
函数, 通过参数指定元素插入的位置. 这个位置之后的所有既有元素, 都会向右移动.
更新元素
List 还提供了函数, 可以替换指定位置的元素 - set()
函数, 以及相应的操作符 []
. set()
函数不会改变其他任何元素的下标.
fill()
函数会将集合的所有元素简单地替换为指定的值.
删除元素
要从 list 的指定位置删除元素, 可以使用 removeAt()
函数, 参数是元素位置. 在这个被删除元素之后的所有其他既有元素, 下标会减少 1.
排序(Sorting)
在 集合排序(Ordering) 中, 我们介绍了按照指定顺序获取集合元素的操作. 对于可变的 list, 标准库提供了类似的扩展函数, 对 list 原地(in place)执行相同的操作. 如果对一个 list 执行这类操作, 它会改变这个 list 实例中的元素顺序.
原地(in place)排序函数的名称与只读 list 的排序函数类似, 但没有 ed/d
后缀:
所有排序函数中的
sorted*
变为sort*
:sort()
,sortDescending()
,sortBy()
, 等等.shuffled()
变为shuffle()
.reversed()
变为reverse()
.
对可变 list 调用 asReversed()
会返回另一个可变 list, 它是原 list 的一个反序视图(reversed view). 在这个视图中的变更会反映到原 list 中. 下面是可变 list 排序函数的示例: