06-区间与迭代

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()  // 而不是手动比较

十、总结

核心要点

  1. 区间(Range)

    • 使用 .. 创建闭区间,until 创建半开区间
    • 支持 downTo 降序和 step 指定步长
    • 可用于 in 判断和 for 循环
  2. 迭代(Iteration)

    • for 循环遍历集合、数组、字符串
    • withIndex() 获取索引和值
    • indices 获取索引范围
  3. 序列(Sequence)

    • 惰性计算,适合大数据集
    • 不创建中间集合,节省内存
    • 使用 asSequence() 转换
  4. 高阶函数

    • mapfilterreducefold
    • 函数式编程风格,代码简洁
    • 链式调用提高可读性
  5. 性能优化

    • 小数据集用集合,大数据集用序列
    • 避免不必要的中间集合
    • 使用专用函数(如 sumOfany

选择指南

场景 推荐方案
数值范围遍历 区间 1..10
集合遍历 for 循环或高阶函数
大数据处理 序列 asSequence()
数据转换 mapfilter
数据聚合 sumreducefold
条件判断 anyallnone

参考资料

相关推荐
gjxDaniel1 天前
Kotlin编程语言入门与常见问题
android·开发语言·kotlin
野生技术架构师1 天前
Java 21虚拟线程 vs Kotlin协程:高并发编程模型的终极对决与选型思考
java·开发语言·kotlin
言之。1 天前
Kotlin快速入门
android·开发语言·kotlin
常利兵1 天前
Android Gradle 构建脚本现代化:Kotlin DSL (.kts) 与 Groovy DSL 深度对比与实战指南
android·开发语言·kotlin
baidu_247438611 天前
Android kotlin 定时n秒完成时回调,含暂停和继续
android·kotlin
stevenzqzq1 天前
kotlin和compose中使用by
kotlin·compose
符哥20081 天前
Android 开发中如何使用Coroutines
android·kotlin
sinat_267611912 天前
跟着官网学习协程随笔
学习·kotlin
缺一句感谢和缺一句道歉2 天前
Module was compiled with an incompatible version of Kotlin.
java·kotlin
灯火不休ᝰ2 天前
[安卓] Kotlin中的架构演进:从MVC到MVVM
android·架构·kotlin