9.1.1.8.1 获取集合的一部分

原文链接: https://kotlinlang.org/docs/collection-parts.html

9.1.1.8.1 获取集合的一部分

Kotlin 标准库包含用于获取集合一部分的扩展函数。这些函数提供了多种为结果集合选择元素的方式:显式列出它们的位置、指定结果大小等等。

切片

slice() 返回由给定索引处的集合元素组成的列表。索引既可以作为区间传入,也可以作为整数值的集合传入。

1
2
3
4
5
6
7

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.slice(1..3))
    println(numbers.slice(0..4 step 2))
    println(numbers.slice(setOf(3, 5, 0)))
}

取前若干元素与丢弃若干元素

要从第一个元素开始获取指定数量的元素,请使用 take() 函数。要获取最后的元素,请使用 takeLast()。当传入的数字大于集合大小时,这两个函数都会返回整个集合。

要取除开头或结尾给定数量之外的所有元素,请分别调用 drop() 和 dropLast() 函数。

1
2
3
4
5
6
7
8

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.take(3))
    println(numbers.takeLast(3))
    println(numbers.drop(1))
    println(numbers.dropLast(5))
}

你也可以用谓词来定义要取或丢弃的元素数量。与上述函数类似的有四个函数:

  • takeWhile() 是带谓词的 take():它取元素直到(但不包括)第一个不匹配谓词的元素。如果第一个集合元素就不匹配谓词,结果为空。
  • takeLastWhile() 与 takeLast() 类似:它从集合末尾开始取匹配谓词的一段元素。这段范围的第一个元素紧接在最后一个不匹配谓词的元素之后。如果最后一个集合元素不匹配谓词,结果为空;
  • dropWhile() 是使用相同谓词的 takeWhile() 的反面:它返回从第一个不匹配谓词的元素开始直到末尾的元素。
  • dropLastWhile() 是使用相同谓词的 takeLastWhile() 的反面:它返回从开头直到最后一个不匹配谓词的元素。
1
2
3
4
5
6
7
8

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five", "six")
    println(numbers.takeWhile { !it.startsWith('f') })
    println(numbers.takeLastWhile { it != "three" })
    println(numbers.dropWhile { it.length == 3 })
    println(numbers.dropLastWhile { it.contains('i') })
}

分块

要把集合拆分成给定大小的若干部分,请使用 chunked() 函数。chunked() 接收一个实参——块的大小——并返回由给定大小的 List 组成的 List。第一块从第一个元素开始,包含 size 个元素;第二块包含接下来的 size 个元素,依此类推。最后一块的大小可能更小。

1
2
3
4
5

fun main() {
    val numbers = (0..13).toList()
    println(numbers.chunked(3))
}

你也可以立即对返回的各块应用转换。为此,请在调用 chunked() 时把转换作为 lambda 函数传入。该 lambda 的实参是集合的一块。当带转换调用 chunked() 时,这些块是短生命周期的 List,应当在该 lambda 中直接消费掉。

1
2
3
4
5

fun main() {
    val numbers = (0..13).toList()
    println(numbers.chunked(3) { it.sum() }) // `it` 是原始集合中的一块
}

滑动窗口

你可以获取给定大小的所有可能的元素区间。用于获取它们的函数叫 windowed():它返回一个重要列表——就像你通过给定大小的滑动窗口观察该集合时看到的所有元素区间。与 chunked() 不同,windowed() 返回的元素区间(窗口)从每个集合元素开始。所有窗口都作为单个 List 的元素返回。

1
2
3
4
5

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.windowed(3))
}

windowed() 在带默认值的参数方面提供了更大的灵活性:

  • step 定义两个相邻窗口的首元素之间的距离。默认值为 1,因此结果包含从所有元素开始的窗口。如果把步长增大到 2,你只会得到从奇数位置元素开始的窗口:第 1 个、第 3 个,依此类推。
  • partialWindows 会包含从集合末尾元素开始的、大小不足的窗口。例如,如果你请求 3 个元素的窗口,对于最后两个元素无法构成完整窗口。此时启用 partialWindows 会额外包含两个大小分别为 2 和 1 的列表。

最后,你可以立即对返回的区间应用转换。为此,请在调用 windowed() 时把转换作为 lambda 函数传入。

1
2
3
4
5
6

fun main() {
    val numbers = (1..10).toList()
    println(numbers.windowed(3, step = 2, partialWindows = true))
    println(numbers.windowed(3) { it.sum() })
}

要构建包含两个元素的窗口,有一个单独的函数——zipWithNext()。它会创建接收者集合中相邻元素组成的对。注意,zipWithNext() 并不会把集合切分成互不重叠的对;它为除最后一个元素之外的每个元素创建一个 Pair,因此它对 [1, 2, 3, 4] 的结果是 [[1, 2], [2, 3], [3, 4]],而不是 [[1, 2]、[3, 4]]。zipWithNext() 也可以带转换函数调用;该函数应当接收接收者集合中的两个元素作为实参。

1
2
3
4
5
6

fun main() {
    val numbers = listOf("one", "two", "three", "four", "five")
    println(numbers.zipWithNext())
    println(numbers.zipWithNext() { s1, s2 -> s1.length > s2.length})
}