迭代器
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())
}