Scala中的迭代器

4 阅读4分钟

Scala 中的迭代器(Iterator)

一、基本概念

迭代器是用于访问集合元素的工具,提供了一种顺序访问元素的方式,而不暴露底层集合的内部结构。

object IteratorBasics {
  def main(args: Array[String]): Unit = {
    // 创建迭代器
    val list = List(1, 2, 3, 4, 5)
    val iterator = list.iterator
    
    println("迭代器基本操作:")
    // 1. hasNext - 检查是否有下一个元素
    println(s"hasNext: ${iterator.hasNext}")
    
    // 2. next - 获取下一个元素
    if (iterator.hasNext) {
      println(s"第一个元素: ${iterator.next()}")
      println(s"第二个元素: ${iterator.next()}")
    }
    
    // 3. 遍历剩余元素
    println("剩余元素:")
    while (iterator.hasNext) {
      println(iterator.next())
    }
    
    // 4. 迭代器只能使用一次
    println(s"\n迭代器已耗尽,hasNext: ${iterator.hasNext}")
    // println(iterator.next())  // 会抛出异常
  }
}

二、迭代器的主要特性

1. 一次性(一次性遍历)

object IteratorOneTime {
  def main(args: Array[String]): Unit = {
    val nums = Vector(10, 20, 30)
    val iter = nums.iterator
    
    println("第一次遍历:")
    while (iter.hasNext) {
      println(iter.next())
    }
    
    println("\n第二次遍历(迭代器已空):")
    // 迭代器已耗尽,不会输出任何内容
    while (iter.hasNext) {
      println(iter.next())  // 不会执行
    }
    println("hasNext: " + iter.hasNext)  // false
  }
}

2. 惰性求值(Lazy Evaluation)

object IteratorLazy {
  def main(args: Array[String]): Unit = {
    // 创建一个大范围的迭代器(不会立即创建所有元素)
    val bigIter = (1 to 1000000).iterator
    
    // 只处理前10个元素
    println("处理前10个元素:")
    bigIter.take(10).foreach(println)
    
    // 元素按需生成,节省内存
    val infiniteIter = Iterator.continually(1)
    println("\n无限迭代器(取前5个):")
    infiniteIter.take(5).foreach(println)
  }
}

3. 不存储状态

object IteratorState {
  def main(args: Array[String]): Unit = {
    val data = Array(1, 2, 3, 4, 5)
    val iter1 = data.iterator
    val iter2 = data.iterator
    
    println("两个独立的迭代器:")
    println("迭代器1: " + iter1.next())  // 1
    println("迭代器2: " + iter2.next())  // 1(独立状态)
    println("迭代器1: " + iter1.next())  // 2
    println("迭代器2: " + iter2.next())  // 2
  }
}

三、常用操作方法

1. 遍历方法

object IteratorTraversal {
  def main(args: Array[String]): Unit = {
    val iter = List("A", "B", "C", "D", "E").iterator
    
    println("方法1: while循环")
    while (iter.hasNext) {
      println(iter.next())
    }
    
    // 重新创建迭代器
    val iter2 = List(1, 2, 3, 4, 5).iterator
    
    println("\n方法2: foreach方法")
    iter2.foreach(println)
    
    println("\n方法3: for循环")
    val iter3 = List("Apple", "Banana", "Cherry").iterator
    for (item <- iter3) {
      println(item)
    }
  }
}

2. 转换操作

object IteratorTransformations {
  def main(args: Array[String]): Unit = {
    val numbers = (1 to 10).iterator
    
    // map - 转换每个元素
    println("Map(每个元素乘以2):")
    val doubled = numbers.map(_ * 2)
    println(doubled.toList)  // 转换为List显示
    
    // filter - 过滤元素
    println("\nFilter(保留偶数):")
    val evens = (1 to 10).iterator.filter(_ % 2 == 0)
    println(evens.toList)
    
    // flatMap - 扁平化映射
    println("\nFlatMap:")
    val words = List("hello", "world").iterator
    val chars = words.flatMap(_.toCharArray)
    println(chars.toList)
  }
}

3. 查找和判断操作

object IteratorSearch {
  def main(args: Array[String]): Unit = {
    val data = List(15, 20, 25, 30, 35).iterator
    
    // find - 查找第一个满足条件的元素
    val found = data.find(_ > 25)
    println(s"第一个大于25的元素: $found")  // Some(30)
    
    // exists - 是否存在满足条件的元素
    val iter2 = List(1, 3, 5, 7, 9).iterator
    val hasEven = iter2.exists(_ % 2 == 0)
    println(s"是否存在偶数: $hasEven")  // false
    
    // forall - 所有元素都满足条件
    val iter3 = List(2, 4, 6, 8).iterator
    val allEven = iter3.forall(_ % 2 == 0)
    println(s"是否都是偶数: $allEven")  // true
  }
}

4. 聚合操作

object IteratorAggregation {
  def main(args: Array[String]): Unit = {
    val numbers = (1 to 5).iterator
    
    // foldLeft - 从左开始聚合
    val sum = numbers.foldLeft(0)(_ + _)
    println(s"Sum: $sum")  // 15
    
    // reduce - 缩减操作
    val iter2 = List(1, 2, 3, 4, 5).iterator
    val product = iter2.reduce(_ * _)
    println(s"Product: $product")  // 120
    
    // count - 计数
    val iter3 = List(1, 2, 3, 4, 5, 6, 7, 8).iterator
    val countEven = iter3.count(_ % 2 == 0)
    println(s"偶数个数: $countEven")  // 4
  }
}

5. 分组和切片操作

object IteratorGrouping {
  def main(args: Array[String]): Unit = {
    val data = (1 to 20).iterator
    
    // take - 取前n个元素
    println("前5个元素:")
    println(data.take(5).toList)
    
    // drop - 跳过前n个元素
    println("\n跳过前3个后的元素:")
    val iter2 = (1 to 10).iterator
    println(iter2.drop(3).toList)
    
    // slice - 获取子序列
    println("\n第3到第7个元素:")
    val iter3 = (1 to 10).iterator
    println(iter3.slice(2, 7).toList)  // 索引从0开始
    
    // grouped - 分组
    println("\n每3个一组:")
    val iter4 = (1 to 10).iterator
    val groups = iter4.grouped(3)
    groups.foreach(group => println(group.toList))
  }
}

四、创建迭代器的多种方式

object IteratorCreation {
  def main(args: Array[String]): Unit = {
    // 1. 从集合创建
    println("1. 从集合创建:")
    val fromList = List(1, 2, 3).iterator
    val fromArray = Array("a", "b", "c").iterator
    val fromSet = Set(1.1, 2.2, 3.3).iterator
    
    // 2. 使用Iterator对象的方法
    println("\n2. Iterator对象方法:")
    
    // range迭代器
    val rangeIter = Iterator.range(1, 10, 2)  // 1,3,5,7,9
    println(s"Range: ${rangeIter.toList}")
    
    // 无限迭代器
    val ones = Iterator.continually(1)
    println(s"无限1(前5个): ${ones.take(5).toList}")
    
    val increment = Iterator.from(5)  // 5,6,7,8,...
    println(s"从5开始(前5个): ${increment.take(5).toList}")
    
    // 3. 迭代多个迭代器
    println("\n3. 迭代多个迭代器:")
    
    // concat - 连接迭代器
    val concatIter = Iterator.concat(
      List(1, 2).iterator,
      List(3, 4).iterator,
      List(5, 6).iterator
    )
    println(s"连接: ${concatIter.toList}")
    
    // zip - 配对
    val letters = List("A", "B", "C").iterator
    val numbers = List(1, 2, 3).iterator
    val zipped = letters.zip(numbers)
    println(s"Zip: ${zipped.toList}")
    
    // 4. 自定义迭代器
    println("\n4. 自定义迭代器:")
    class FibonacciIterator extends Iterator[Int] {
      private var prev = 0
      private var current = 1
      
      override def hasNext: Boolean = true  // 无限序列
      
      override def next(): Int = {
        val result = prev
        prev = current
        current = result + current
        result
      }
    }
    
    val fib = new FibonacciIterator
    println(s"斐波那契数列(前10个): ${fib.take(10).toList}")
  }
}

五、实际应用场景

1. 处理大文件

import scala.io.Source

object LargeFileProcessor {
  def main(args: Array[String]): Unit = {
    // 使用迭代器逐行处理大文件
    val source = Source.fromFile("data/large_file.txt")
    val lines = source.getLines()  // 返回迭代器
    
    println("处理大文件(取前5行):")
    lines.take(5).foreach(line => {
      // 处理每一行,不会一次性加载到内存
      println(s"处理行: ${line.take(50)}...")
    })
    
    source.close()
  }
}

2. 流式数据处理

object StreamProcessing {
  def main(args: Array[String]): Unit = {
    // 模拟流式数据源
    def dataStream: Iterator[Int] = {
      // 在实际应用中可能来自网络、传感器等
      Iterator.from(1).map { n =>
        Thread.sleep(100)  // 模拟延迟
        n * 10
      }
    }
    
    println("流式数据处理:")
    val processed = dataStream
      .filter(_ % 20 == 0)  // 过滤
      .map(_ / 2)           // 转换
      .take(5)              // 限制数量
    
    processed.foreach(item => println(s"处理结果: $item"))
  }
}

3. 分页处理

object Pagination {
  def main(args: Array[String]): Unit = {
    // 模拟数据库查询结果
    val allData = (1 to 100).iterator
    
    def getPage(page: Int, pageSize: Int): List[Int] = {
      val start = (page - 1) * pageSize
      allData.slice(start, start + pageSize).toList
    }
    
    println("第1页(每页10条):")
    println(getPage(1, 10))
    
    println("\n第2页(每页10条):")
    println(getPage(2, 10))
  }
}

六、注意事项和最佳实践

object IteratorBestPractices {
  def main(args: Array[String]): Unit = {
    // 1. 不要重复使用已耗尽的迭代器
    val iter = List(1, 2, 3).iterator
    iter.foreach(println)  // 消耗迭代器
    
    // val sum = iter.sum  // 错误!迭代器已空
    
    // 正确做法:重新创建
    val newIter = List(1, 2, 3).iterator
    println(s"重新创建的迭代器求和: ${newIter.sum}")
    
    // 2. 避免在遍历过程中修改底层集合
    val list = scala.collection.mutable.ListBuffer(1, 2, 3)
    val badIter = list.iterator
    
    // 遍历时修改集合可能导致不确定行为
    // list += 4  // 危险操作!
    
    // 3. 对于需要多次遍历的情况,使用集合而不是迭代器
    val data = List(1, 2, 3, 4, 5)
    
    // 需要多次访问时
    println(s"第一次访问: ${data.sum}")
    println(s"第二次访问: ${data.product}")
    
    // 4. 使用视图(View)进行惰性链式操作
    val result = (1 to 1000000).view
      .filter(_ % 2 == 0)
      .map(_ * 2)
      .take(10)
      .toList
    
    println(s"使用视图处理: $result")
  }
}

总结

迭代器的优点:

  • 惰性求值,节省内存
  • 适合处理大量或无限数据
  • 提供丰富的操作链
  • 不存储数据,只提供访问方式

迭代器的缺点:

  • 只能遍历一次
  • 不能随机访问
  • 某些操作可能效率较低

选择建议:

  • 处理大文件或流数据 → 使用迭代器
  • 需要多次访问数据 → 使用集合
  • 需要惰性处理链 → 使用视图或迭代器
  • 需要随机访问 → 使用数组或索引序列