迭代器思想

206 阅读1分钟

迭代器

val source = List(
  "hello world",
  "hello hello",
  "hello scala",
  "hello java"
)
source.filter(!_.isEmpty)
  .flatMap(_.split("\\s"))
  .map((_, 1))
  .groupBy(_._1)
  .foreach(println)

和下面对比

val itr1 = source.iterator
val itr2 = itr1.flatMap(_.split("\\s"))
val itr3 = itr2.map((_, 1))
itr3.foreach(println)
  • 两段代码都是 Scala操作数据集api 目的就是计算wordcount。
  • 第一段代码每个算子都会产生一个新的数据集在内存中。这样一看在处理大数据时,内存消耗明显。
  • 第二段代码 使用原始数据集产生迭代器。 对迭代器操作返回还是迭代器,代码直接到最后foreach的时候整体才开始走。

flatmap怎么玩的 和map的区别

  • 迭代器的flatMap方法源码如下。可以看出flatMap的返回值也是一个迭代器。
  • 只要是迭代器就有next和hashNext方法。
/** The iterator which produces no values. */
val empty: Iterator[Nothing] = new AbstractIterator[Nothing] {
def hasNext: Boolean = false
def next(): Nothing = throw new NoSuchElementException("next on empty iterator")
}


def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
// 这初始化的时候给了一个empty 就是上面的代码。
private var cur: Iterator[B] = empty
// 这的f就是咱给flatMap中传的函数 这是flatMap的核心所在 也就是为什么能扁平化    self是数据集的迭代器。
private def nextCur() { cur = f(self.next()).toIterator }
def hasNext: Boolean = {
  // Equivalent to cur.hasNext || self.hasNext && { nextCur(); hasNext }
  // but slightly shorter bytecode (better JVM inlining!)
  while (!cur.hasNext) {
    if (!self.hasNext) return false
    nextCur()
  }
  true
}
// 调用next 真正的开始指针的挪动
def next(): B = (if (hasNext) cur else empty).next()
}
  • 迭代器的map方法如下,也是返回了一个迭代器。map是 一对一操作 所以直接调用上一层迭代器
  • 在next方法中 有f是自己传入的函数。
def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
def hasNext = self.hasNext
def next() = f(self.next())
}