# List 相关操作
[List](collections-overview.html#list) 是 Kotlin 内建集合中最常用的类型. 基于下标的元素访问, 为 list 提供了很多功能强大的操作.
## 使用下标获取元素
List 支持所有集合共通的元素获取操作: `elementAt()`, `first()`, `last()`, 以及在 [获取集合的单个元素](collection-elements.html) 中介绍的其他操作. List 独有的功能是使用下标访问元素, 因此读取一个元素的最简单方法是使用下标来访问它. 这个功能通过 [get()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/get.html) 函数实现, 参数是元素下标, 或者也可以使用更简短的 `[index]` 语法.
如果 list 大小小于指定的下标, 会抛出一个异常. 另外两个其他函数, 可以避免这类异常:
* [getOrElse()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-or-else.html) 允许指定一个函数, 如果下标在集合中不存在, 可以通过这个函数来计算一个默认值.
* [getOrNull()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-or-null.html) 返回 `null` 作为下标不存在时的默认值.
```KOTLIN
fun main() {
//sampleStart
val numbers = listOf(1, 2, 3, 4)
println(numbers.get(0))
println(numbers[0])
//numbers.get(5) // 发生异常!
println(numbers.getOrNull(5)) // 返回 null
println(numbers.getOrElse(5, {it})) // 返回 5
//sampleEnd
}
```
## 获取 list 的一部分
除了 [获取集合的一部分](collection-parts.html) 中介绍过的共通操作之外, list 还提供了一个 [subList()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/sub-list.html) 函数, 它返回 list 中某个指定的下标范围中的元素构成的视图(view). 因此, 如果原集合中的元素发生变化, 那么在之前创建的子列表中它也会变化, 反过来也是如此.
```KOTLIN
fun main() {
//sampleStart
val numbers = (0..13).toList()
println(numbers.subList(3, 6))
//sampleEnd
}
```
## 查找元素位置
### 线性查找(Linear Search)
对任何 list, 你可以使用 [indexOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of.html) 和 [lastIndexOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/last-index-of.html) 函数查找一个元素的位置. 这些函数返回 list 中第一个和最后一个与参数相等的元素的位置. 如果不存在匹配的元素, 这两个函数都返回 `-1`.
```KOTLIN
fun main() {
//sampleStart
val numbers = listOf(1, 2, 3, 4, 2, 5)
println(numbers.indexOf(2))
println(numbers.lastIndexOf(2))
//sampleEnd
}
```
还有另一组函数, 接收的参数是一个判定条件, 并查找满足判定条件的元素:
* [indexOfFirst()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of-first.html) 返回满足判定条件的 第一个元素的下标, 如果不存在匹配的元素, 则返回 `-1`.
* [indexOfLast()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/index-of-last.html) 返回满足判定条件的 最后一个元素的下标, 如果不存在匹配的元素, 则返回 `-1`.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4)
println(numbers.indexOfFirst { it > 2})
println(numbers.indexOfLast { it % 2 == 1})
//sampleEnd
}
```
### 在排序的 list 中折半查找(Binary Search)
在 list 中查找元素还有另一种方式 – [折半查找(Binary Search)](https://en.wikipedia.org/wiki/Binary_search_algorithm). 这种方法的速度要比其他内建函数快很多, 但它 要求 list 按照升序 [排序](collection-ordering.html), 排序方法可以是: 自然顺序, 或通过函数参数指定的其它顺序. 否则, 这个函数的查找结果是不确定的.
要在排序的 list 中查找一个元素, 请使用 [binarySearch()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/binary-search.html) 函数, 要查找的元素作为参数. 如果这个元素存在, 这个函数返回它的下标; 否则, 它返回 `(-insertionPoint - 1)`, 其中的 `insertionPoint` 是为了保持 list 正确排序, 这个元素应该插入的下标. 如果存在多个元素等于指定的值, 查找结果可能返回其中任何一个的下标.
也可以指定查找的下标范围: 这种情况下, 这个函数只在指定的两个下标之间进行查找.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println(numbers)
println(numbers.binarySearch("two")) // 结果是 3
println(numbers.binarySearch("z")) // 结果是 -5
println(numbers.binarySearch("two", 0, 2)) // 结果是 -3
//sampleEnd
}
```
#### 使用比较器(Comparator)进行折半查找(Binary Search)
如果 list 元素不是 `Comparable` 对象, 那么在进行折半查找(Binary Search)时, 需要提供一个 [Comparator](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-comparator/). list 中的元素必须按这个 `Comparator` 比较的结果升序排列. 下面我们来看看示例程序:
```KOTLIN
data class Product(val name: String, val price: Double)
fun main() {
//sampleStart
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch(Product("AppCode", 99.0), compareBy { it.price }.thenBy { it.name }))
//sampleEnd
}
```
这里我们有一个 `Product` 的 list, 其中的 `Product` 对象不是 `Comparable`, 然后我们通过一个 `Comparator` 定义了它们的排序方式: 如果 `p1` 的价格低于 `p2`, 则产品 `p1` 排在 `p2` 之前. 因此, 首先让 list 按照这个规则升序排列, 然后我们使用 `binarySearch()` 来查找指定的 `Product` 的下标.
如果 list 中的元素是 `Comparable` 对象, 但不使用其自然顺序, 比如, 对 `String` 不区分大小写排序的情况, 这时自定义的比较器也是很方便的.
```KOTLIN
fun main() {
//sampleStart
val colors = listOf("Blue", "green", "ORANGE", "Red", "yellow")
println(colors.binarySearch("RED", String.CASE_INSENSITIVE_ORDER)) // 结果是 3
//sampleEnd
}
```
#### 使用比较(Comparison)函数进行折半查找(Binary Search)
进行折半查找(Binary Search)时, 使用 比较(Comparison) 函数, 不必指定确切的查找值即可查找元素. 这种查找方法不需要具体的元素值, 而是接受一个比较函数, 比较函数负责将元素变换为 `Int` 值, 然后查找变换结果为 0 的元素. list 必须按照比较函数规定的升序排序; 也就是说, list 中各个元素传递给比较函数之后的返回值必须是递增的.
```KOTLIN
import kotlin.math.sign
//sampleStart
data class Product(val name: String, val price: Double)
fun priceComparison(product: Product, price: Double) = sign(product.price - price).toInt()
fun main() {
val productList = listOf(
Product("WebStorm", 49.0),
Product("AppCode", 99.0),
Product("DotTrace", 129.0),
Product("ReSharper", 149.0))
println(productList.binarySearch { priceComparison(it, 99.0) })
}
//sampleEnd
```
使用比较器(Comparator)和比较(Comparison)函数的折半查找, 也同样可以针对 list 的下标范围进行查找.
## List 的写入操作
除了 [集合写入操作](collection-write.html) 中介绍的集合共通的写操作之外, [可变(mutable)](collections-overview.html#collection-types) list 还支持 list 独有的写操作. 这类操作使用下标访问元素的方式进行, 增加了 list 的修改能力.
### 添加元素
要将元素添加到 list 的指定位置, 可以使用 [add()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/add.html) 和 [addAll()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/add-all.html) 函数, 通过参数指定元素插入的位置. 这个位置之后的所有既有元素, 都会向右移动.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf("one", "five", "six")
numbers.add(1, "two")
numbers.addAll(2, listOf("three", "four"))
println(numbers)
//sampleEnd
}
```
### 更新元素
List 还提供了函数, 可以替换指定位置的元素 - [set()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/set.html) 函数, 以及相应的操作符 `[]`. `set()` 函数不会改变其他任何元素的下标.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf("one", "five", "three")
numbers[1] = "two"
println(numbers)
//sampleEnd
}
```
[fill()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/fill.html) 函数会将集合的所有元素简单地替换为指定的值.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4)
numbers.fill(3)
println(numbers)
//sampleEnd
}
```
### 删除元素
要从 list 的指定位置删除元素, 可以使用 [removeAt()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/remove-at.html) 函数, 参数是元素位置. 在这个被删除元素之后的所有其他既有元素, 下标会减少 1.
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf(1, 2, 3, 4, 3)
numbers.removeAt(1)
println(numbers)
//sampleEnd
}
```
### 排序
在 [集合排序(Ordering)](collection-ordering.html) 中, 我们介绍了按照指定顺序获取集合元素的操作. 对于可变的 list, 标准库提供了类似的扩展函数, 对 list 原地(In Place)执行相同的操作. 如果对一个 list 执行这类操作, 它会改变这个 list 实例中的元素顺序.
原地(In Place)排序函数的名称与只读 list 的排序函数类似, 但没有 `ed/d` 后缀:
* 所有排序函数中的 `sorted*` 变为 `sort*`: [sort()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sort.html), [sortDescending()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sort-descending.html), [sortBy()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sort-by.html), 等等.
* `shuffled()` 变为 [shuffle()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/shuffle.html).
* `reversed()` 变为 [reverse()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/reverse.html).
对可变 list 调用 [asReversed()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/as-reversed.html) 会返回另一个可变 list, 它是原 list 的一个反序视图(reversed view). 在这个视图中的变更会反映到原 list 中. 下面是可变 list 排序函数的示例:
```KOTLIN
fun main() {
//sampleStart
val numbers = mutableListOf("one", "two", "three", "four")
numbers.sort()
println("Sort into ascending: $numbers")
numbers.sortDescending()
println("Sort into descending: $numbers")
numbers.sortBy { it.length }
println("Sort into ascending by length: $numbers")
numbers.sortByDescending { it.last() }
println("Sort into descending by the last letter: $numbers")
numbers.sortWith(compareBy { it.length }.thenBy { it })
println("Sort by Comparator: $numbers")
numbers.shuffle()
println("Shuffle: $numbers")
numbers.reverse()
println("Reverse: $numbers")
//sampleEnd
}
```