06 - Kotlin 区间与迭代
本章介绍 Kotlin 的区间(Range)操作和迭代(Iteration)方式。
一、区间(Range)
1.1 创建区间
kotlin
// 闭区间(包含起始和结束)
val range1 = 1..5 // [1, 2, 3, 4, 5]
// 半开区间(不包含结束)
val range2 = 1 until 5 // [1, 2, 3, 4]
// 降序区间
val range3 = 5 downTo 1 // [5, 4, 3, 2, 1]
// 指定步长
val range4 = 1..10 step 2 // [1, 3, 5, 7, 9]
val range5 = 10 downTo 1 step 2 // [10, 8, 6, 4, 2]
1.2 区间类型
| 类型 | 示例 | 说明 |
|---|---|---|
IntRange |
1..10 |
整数区间 |
LongRange |
1L..10L |
长整数区间 |
CharRange |
'a'..'z' |
字符区间 |
kotlin
val intRange: IntRange = 1..10
val longRange: LongRange = 1L..10L
val charRange: CharRange = 'a'..'z'
1.3 区间判断
kotlin
val x = 5
// 检查是否在区间内
if (x in 1..10) {
println("x 在区间内")
}
// 检查是否不在区间内
if (x !in 1..3) {
println("x 不在区间内")
}
// 实际应用:数据验证
fun validateAge(age: Int): Boolean {
return age in 0..150
}
fun validateScore(score: Int): String {
return when (score) {
in 90..100 -> "优秀"
in 80..89 -> "良好"
in 70..79 -> "中等"
in 60..69 -> "及格"
in 0..59 -> "不及格"
else -> "无效分数"
}
}
// 字符区间判断
fun isLowerCase(char: Char) = char in 'a'..'z'
fun isUpperCase(char: Char) = char in 'A'..'Z'
fun isDigit(char: Char) = char in '0'..'9'
// 多区间判断
fun isVowel(char: Char): Boolean {
return char.lowercaseChar() in setOf('a', 'e', 'i', 'o', 'u')
}
1.4 区间遍历
kotlin
// 正序遍历
for (i in 1..5) {
print("$i ") // 1 2 3 4 5
}
// 倒序遍历
for (i in 5 downTo 1) {
print("$i ") // 5 4 3 2 1
}
// 步长遍历
for (i in 1..10 step 2) {
print("$i ") // 1 3 5 7 9
}
二、迭代(Iteration)
2.1 遍历集合
kotlin
val list = listOf("a", "b", "c")
// 遍历元素
for (item in list) {
println(item)
}
// 带索引遍历
for ((index, item) in list.withIndex()) {
println("$index: $item")
}
// 使用索引
for (i in list.indices) {
println("${i}: ${list[i]}")
}
2.2 遍历数组
kotlin
val array = arrayOf(1, 2, 3, 4, 5)
for (item in array) {
println(item)
}
for ((index, value) in array.withIndex()) {
println("$index: $value")
}
2.3 遍历字符串
kotlin
val text = "Kotlin"
for (char in text) {
println(char)
}
for ((index, char) in text.withIndex()) {
println("$index: $char")
}
2.4 遍历 Map
kotlin
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
for ((key, value) in map) {
println("$key: $value")
}
// 只遍历键
for (key in map.keys) {
println(key)
}
// 只遍历值
for (value in map.values) {
println(value)
}
三、迭代器(Iterator)
3.1 使用迭代器
kotlin
val list = listOf(1, 2, 3, 4, 5)
val iterator = list.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
println(item)
}
3.2 可变迭代器
kotlin
val mutableList = mutableListOf(1, 2, 3, 4, 5)
val iterator = mutableList.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
if (item % 2 == 0) {
iterator.remove() // 删除偶数
}
}
println(mutableList) // [1, 3, 5]
四、序列(Sequence)
4.1 创建序列
kotlin
// 从集合创建
val sequence1 = listOf(1, 2, 3).asSequence()
// 使用 sequenceOf
val sequence2 = sequenceOf(1, 2, 3, 4, 5)
// 使用 generateSequence
val sequence3 = generateSequence(1) { it + 1 } // 无限序列
4.2 序列操作
kotlin
val numbers = (1..1_000_000).asSequence()
.filter { it % 2 == 0 }
.map { it * it }
.take(5)
.toList()
println(numbers) // [4, 16, 36, 64, 100]
// 实际应用:处理大文件
fun processLargeFile(filePath: String) {
File(filePath).useLines { lines ->
lines.asSequence()
.filter { it.isNotBlank() }
.map { it.trim() }
.take(100)
.forEach { println(it) }
}
}
// 无限序列
val fibonacci = generateSequence(0 to 1) { (a, b) -> b to a + b }
.map { it.first }
.take(10)
.toList()
println(fibonacci) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
4.3 序列 vs 集合
| 特性 | 集合 | 序列 |
|---|---|---|
| 计算方式 | 立即计算 | 惰性计算 |
| 中间操作 | 每次创建新集合 | 延迟到终端操作 |
| 适用场景 | 小数据集 | 大数据集或无限序列 |
kotlin
// 集合:立即计算
val list = listOf(1, 2, 3, 4, 5)
.filter { println("filter $it"); it % 2 == 0 }
.map { println("map $it"); it * 2 }
// 序列:惰性计算
val sequence = listOf(1, 2, 3, 4, 5).asSequence()
.filter { println("filter $it"); it % 2 == 0 }
.map { println("map $it"); it * 2 }
.toList() // 此时才开始计算
五、高阶函数迭代
5.1 forEach
kotlin
listOf(1, 2, 3).forEach { println(it) }
listOf(1, 2, 3).forEachIndexed { index, value ->
println("$index: $value")
}
5.2 map
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
println(doubled) // [2, 4, 6, 8, 10]
5.3 filter
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val even = numbers.filter { it % 2 == 0 }
println(even) // [2, 4]
5.4 reduce / fold
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
// reduce:从第一个元素开始累积
val sum = numbers.reduce { acc, i -> acc + i }
println(sum) // 15
// fold:指定初始值
val product = numbers.fold(1) { acc, i -> acc * i }
println(product) // 120
// 实际应用:字符串拼接
val words = listOf("Kotlin", "is", "awesome")
val sentence = words.reduce { acc, word -> "$acc $word" }
println(sentence) // Kotlin is awesome
// 计算最大值
val max = numbers.reduce { acc, i -> if (i > acc) i else acc }
println(max) // 5
// fold 的优势:可以改变返回类型
val lengths = words.fold(0) { acc, word -> acc + word.length }
println(lengths) // 15
// foldRight:从右向左累积
val result = listOf("a", "b", "c").foldRight("") { str, acc -> acc + str }
println(result) // cba
5.5 any / all / none
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
// any:是否存在满足条件的元素
val hasEven = numbers.any { it % 2 == 0 }
println(hasEven) // true
// all:是否所有元素都满足条件
val allPositive = numbers.all { it > 0 }
println(allPositive) // true
// none:是否没有元素满足条件
val noNegative = numbers.none { it < 0 }
println(noNegative) // true
// 实际应用:表单验证
data class User(val name: String, val age: Int, val email: String)
val users = listOf(
User("Alice", 25, "alice@example.com"),
User("Bob", 17, "bob@example.com"),
User("Charlie", 30, "charlie@example.com")
)
val allAdults = users.all { it.age >= 18 } // false
val hasMinor = users.any { it.age < 18 } // true
val noEmptyName = users.none { it.name.isBlank() } // true
5.6 find / first / last
kotlin
val numbers = listOf(1, 2, 3, 4, 5)
// find:查找第一个满足条件的元素(找不到返回 null)
val firstEven = numbers.find { it % 2 == 0 }
println(firstEven) // 2
// findLast:查找最后一个满足条件的元素
val lastEven = numbers.findLast { it % 2 == 0 }
println(lastEven) // 4
// first:获取第一个元素(空集合会抛异常)
val first = numbers.first()
println(first) // 1
// firstOrNull:安全获取第一个元素
val firstOrNull = emptyList<Int>().firstOrNull()
println(firstOrNull) // null
// first with predicate:获取第一个满足条件的元素
val firstGreaterThan3 = numbers.first { it > 3 }
println(firstGreaterThan3) // 4
// last:获取最后一个元素
val last = numbers.last()
println(last) // 5
六、实用示例
6.1 九九乘法表
kotlin
for (i in 1..9) {
for (j in 1..i) {
print("$j×$i=${i*j}\t")
}
println()
}
6.2 查找素数
kotlin
fun isPrime(n: Int): Boolean {
if (n <= 1) return false
if (n == 2) return true
if (n % 2 == 0) return false
// 优化:只检查到 sqrt(n)
for (i in 3..Math.sqrt(n.toDouble()).toInt() step 2) {
if (n % i == 0) return false
}
return true
}
// 使用区间查找素数
val primes = (2..100).filter { isPrime(it) }
println(primes)
// 使用序列优化大范围查找
val largePrimes = (2..10000).asSequence()
.filter { isPrime(it) }
.take(100)
.toList()
6.3 反转字符串
kotlin
fun reverseString(text: String): String {
var result = ""
for (i in text.length - 1 downTo 0) {
result += text[i]
}
return result
}
println(reverseString("Kotlin")) // niltoK
6.4 斐波那契数列
kotlin
// 使用序列生成
val fibonacci = generateSequence(Pair(0, 1)) { Pair(it.second, it.first + it.second) }
.map { it.first }
.take(10)
.toList()
println(fibonacci) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
// 使用循环生成
fun fibonacciList(n: Int): List<Long> {
if (n <= 0) return emptyList()
if (n == 1) return listOf(0)
val result = mutableListOf(0L, 1L)
for (i in 2 until n) {
result.add(result[i - 1] + result[i - 2])
}
return result
}
println(fibonacciList(10)) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
6.5 数字金字塔
kotlin
// 打印数字金字塔
fun printNumberPyramid(rows: Int) {
for (i in 1..rows) {
// 打印空格
repeat(rows - i) { print(" ") }
// 打印数字
for (j in 1..i) {
print("$j ")
}
println()
}
}
printNumberPyramid(5)
/*
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
*/
// 打印星号金字塔
fun printStarPyramid(rows: Int) {
for (i in 1..rows) {
repeat(rows - i) { print(" ") }
repeat(2 * i - 1) { print("*") }
println()
}
}
6.6 矩阵操作
kotlin
// 创建矩阵
fun createMatrix(rows: Int, cols: Int): Array<IntArray> {
return Array(rows) { row ->
IntArray(cols) { col -> row * cols + col + 1 }
}
}
// 打印矩阵
fun printMatrix(matrix: Array<IntArray>) {
for (row in matrix) {
for (value in row) {
print("$value\t")
}
println()
}
}
// 矩阵转置
fun transpose(matrix: Array<IntArray>): Array<IntArray> {
val rows = matrix.size
val cols = matrix[0].size
return Array(cols) { col ->
IntArray(rows) { row -> matrix[row][col] }
}
}
// 使用
val matrix = createMatrix(3, 4)
printMatrix(matrix)
println("转置后:")
printMatrix(transpose(matrix))
6.7 数据统计
kotlin
data class Sale(val product: String, val amount: Double, val quantity: Int)
val sales = listOf(
Sale("Apple", 100.0, 10),
Sale("Banana", 50.0, 20),
Sale("Apple", 150.0, 15),
Sale("Orange", 80.0, 8)
)
// 按产品分组统计
val salesByProduct = sales.groupBy { it.product }
.mapValues { (_, sales) ->
sales.sumOf { it.amount }
}
println(salesByProduct) // {Apple=250.0, Banana=50.0, Orange=80.0}
// 计算总销售额
val totalAmount = sales.sumOf { it.amount }
println("总销售额: $totalAmount")
// 找出销量最高的产品
val topProduct = sales.groupBy { it.product }
.mapValues { (_, sales) -> sales.sumOf { it.quantity } }
.maxByOrNull { it.value }
println("销量最高: $topProduct")
// 计算平均单价
val avgPrice = sales.map { it.amount / it.quantity }
.average()
println("平均单价: $avgPrice")
七、性能优化技巧
7.1 序列 vs 集合的选择
kotlin
// 小数据集:使用集合(立即计算)
val smallList = listOf(1, 2, 3, 4, 5)
.filter { it % 2 == 0 }
.map { it * it }
// 大数据集:使用序列(惰性计算)
val largeSequence = (1..1_000_000).asSequence()
.filter { it % 2 == 0 }
.map { it * it }
.take(10)
.toList()
// 多次操作:序列更高效
val result = (1..1000).asSequence()
.filter { it % 2 == 0 }
.map { it * 2 }
.filter { it > 100 }
.take(5)
.toList()
7.2 避免不必要的中间集合
kotlin
// ❌ 低效:创建多个中间集合
val result1 = list
.filter { it > 0 }
.map { it * 2 }
.filter { it < 100 }
// ✅ 高效:合并条件
val result2 = list
.filter { it > 0 && it * 2 < 100 }
.map { it * 2 }
// ✅ 使用序列
val result3 = list.asSequence()
.filter { it > 0 }
.map { it * 2 }
.filter { it < 100 }
.toList()
7.3 使用专用函数
kotlin
// ❌ 低效
val sum1 = list.map { it * 2 }.reduce { acc, i -> acc + i }
// ✅ 高效
val sum2 = list.sumOf { it * 2 }
// ❌ 低效
val hasEven1 = list.filter { it % 2 == 0 }.isNotEmpty()
// ✅ 高效
val hasEven2 = list.any { it % 2 == 0 }
八、区间与迭代对比
| 操作 | 区间 | 迭代 |
|---|---|---|
| 用途 | 表示数值范围 | 遍历元素 |
| 创建 | 1..10 |
for (i in list) |
| 判断 | x in 1..10 |
- |
| 步长 | 1..10 step 2 |
- |
| 倒序 | 10 downTo 1 |
reversed() |
| 性能 | 常量空间 | 取决于集合大小 |
集合操作 vs 序列操作
| 特性 | 集合操作 | 序列操作 |
|---|---|---|
| 计算时机 | 立即计算 | 惰性计算 |
| 中间结果 | 创建新集合 | 不创建中间集合 |
| 内存占用 | 较高 | 较低 |
| 适用场景 | 小数据集、需要多次访问 | 大数据集、单次遍历 |
| 性能 | 小数据集更快 | 大数据集更快 |
九、常见陷阱与最佳实践
9.1 区间边界问题
kotlin
// ⚠️ 注意:.. 是闭区间,包含结束值
for (i in 0..array.size) { // ❌ 会越界
println(array[i])
}
// ✅ 使用 until 或 indices
for (i in 0 until array.size) { // ✅ 正确
println(array[i])
}
for (i in array.indices) { // ✅ 更好
println(array[i])
}
9.2 空集合处理
kotlin
val emptyList = emptyList<Int>()
// ❌ 会抛异常
// val first = emptyList.first()
// ✅ 安全处理
val first = emptyList.firstOrNull()
val max = emptyList.maxOrNull()
val sum = emptyList.sum() // 返回 0
9.3 修改正在迭代的集合
kotlin
val list = mutableListOf(1, 2, 3, 4, 5)
// ❌ 会抛 ConcurrentModificationException
// for (item in list) {
// if (item % 2 == 0) {
// list.remove(item)
// }
// }
// ✅ 使用迭代器
val iterator = list.iterator()
while (iterator.hasNext()) {
if (iterator.next() % 2 == 0) {
iterator.remove()
}
}
// ✅ 创建新集合
val filtered = list.filter { it % 2 != 0 }
// ✅ 使用 removeIf
list.removeIf { it % 2 == 0 }
9.4 最佳实践总结
kotlin
// ✅ 优先使用不可变集合
val list = listOf(1, 2, 3)
// ✅ 使用函数式操作代替循环
val doubled = list.map { it * 2 } // 而不是手动循环
// ✅ 链式调用保持简洁
val result = list
.filter { it > 0 }
.map { it * 2 }
.take(5)
// ✅ 大数据集使用序列
val largeResult = (1..1_000_000).asSequence()
.filter { it % 2 == 0 }
.take(100)
.toList()
// ✅ 使用专用函数
val sum = list.sum() // 而不是 reduce
val max = list.maxOrNull() // 而不是手动比较
十、总结
核心要点
-
区间(Range)
- 使用
..创建闭区间,until创建半开区间 - 支持
downTo降序和step指定步长 - 可用于
in判断和for循环
- 使用
-
迭代(Iteration)
for循环遍历集合、数组、字符串withIndex()获取索引和值indices获取索引范围
-
序列(Sequence)
- 惰性计算,适合大数据集
- 不创建中间集合,节省内存
- 使用
asSequence()转换
-
高阶函数
map、filter、reduce、fold等- 函数式编程风格,代码简洁
- 链式调用提高可读性
-
性能优化
- 小数据集用集合,大数据集用序列
- 避免不必要的中间集合
- 使用专用函数(如
sumOf、any)
选择指南
| 场景 | 推荐方案 |
|---|---|
| 数值范围遍历 | 区间 1..10 |
| 集合遍历 | for 循环或高阶函数 |
| 大数据处理 | 序列 asSequence() |
| 数据转换 | map、filter |
| 数据聚合 | sum、reduce、fold |
| 条件判断 | any、all、none |