1. flatMap、map

集合使用flatMap和map来处理数据

val listStr01 = List("hello word", "hello hdfs", "hadoop hdfs")

//原版写法、flatMap扁平化

// val listStr02 = listStr01.flatMap((x:String) =>x.split(" "))

val listStr02 = listStr01.flatMap(_.split(" "))//简化版匿名函数 、按空格切割、将listStr01中三个元素切分成六个并放入新的list中

listStr02.foreach(println)

// 如何将list转换为map

println("---------------将list转换成map--------------")

val listToMap = listStr02.map((_, 1))//map就是映射 _就是数据,以数据当key 1就是固定的value

listToMap.foreach(println)

缺点:内存扩大了n倍、每一步计算内存都保留对象数据、 什么技术可以解决数据计算中间状态占用内存这一问题? iterator迭代器

2. 什么是迭代器、为什么会有迭代器模式

在集合中、因为迭代器迭代时是通过指针进行迭代的、如果多线程同时迭代一个集合的话 第一个迭代器迭代到指针3的时候 第二个迭代器来了、它迭代的话是从指针3开始迭代的、并不是从头开始迭代、它存放的只有指针

优化代码:

val it = listStr01.iterator //什么是迭代器、为什么会有迭代器模式、 迭代器里不存数据

// 集合中 因为迭代器迭代时是通过指针进行迭代的、如果多线程同时迭代一个集合的话 第一个迭代器迭代到指针3的时候 第二个迭代器来了、它迭代的话是从指针3开始迭代的、并不是从指针1开始迭代

val itStr02 = it.flatMap(_.split(" "))//简化版匿名函数 、按空格切割、将listStr01中三个元素切分成六个并放入新的list中

// itStr02.foreach(println)

// 如何将list转换为map

val itStr02tToMap = itStr02.map((_, 1))//map就是映射 _就是数据,以数据当key 1就是固定的value

itStr02tToMap.foreach(println) //这里不出现数据是因为上面 itStr02 遍历的时候将迭代器的指针跌倒到最后了、所以将上面foreach注释了就可以了

2.1 首先我们来看迭代器的源码

2.2 当咱们数据集进行迭代时、它首先会去new 一个抽象的迭代器、其中包含hashNext 和 next 方法,

//按照我的理解 StrictOptimizedLinearSeqOps.this 代表它自己、例:当前的那个数据集合

private[this] var current = StrictOptimizedLinearSeqOps.this

// 取反、如果当前无数据 会返回false

def hasNext = !current.isEmpty

// 它是将集合的首位、头部赋值给了r、然后将集合头部往后的数据重新赋给了current、返回一个r 如果是while循环的话 它会一直往后取、直到current.tail赋给current 为空的时候,走到def hasNext = !current.isEmpty 返回一个false 然后结束

def next() = { val r = current.head; current = current.tail; r }

2.3 接着咱们使用迭代器调用flatMap方法的时候 val itStr02 = it.flatMap(_.split(" "))

它还是会先new 一个抽象的迭代器、默认给cur置空、_hasNext默认设置为 -1 ,接着咱们看它flatMap的hasNext、和next方法

def hasNext: Boolean = {

//因为默认值给了-1

if (_hasNext == -1) {

//cur 取反 为true

while (!cur.hasNext) {

//self代表自己、意思说当前方法的迭代器、它问父迭代器有没有数据、咱们是通过it.flatMap(_.split(" "))调用的,如果父迭代器告诉他有数据那就取反为false不进行if后的操作

if (!self.hasNext) {

_hasNext = 0

// since we know we are exhausted, we can release cur for gc, and as well replace with

// static Iterator.empty which will support efficient subsequent `hasNext`/`next` calls

cur = Iterator.empty

return false

}

//父迭代器有数据将会调用这个方法

nextCur()

}

_hasNext = 1

true

} else _hasNext == 1

}

flatMap的nextCur方法:

private[this] def nextCur(): Unit = {

cur = null

//令cur 进行赋值、意思是从父迭代器中拿出了一条元素(hello word),传给我们的方法就是前面定义的split、然后将数组转换成迭代器付给了cur

cur = f(self.next()).iterator

_hasNext = -1

}

flatMap的next 方法

def next(): B = {

//这里的话它是看hasNext这个方法有没有值有的话不执行

if (hasNext) {

_hasNext = -1

}

//它会得到hasNaxt中split切割的数据、按照数据集来看就是 hello

cur.next()

}

这里最重要的就是cur,只要下游掉了hasNext 方法 cur为空 hasNaxt方法就会偷摸填充cur、下游只要掉next方法、next只会从cur中取元素返回给下游

2.3 咱们看 map方法、它也是new 一个抽象迭代器,它就负责掉父亲的hasNext和next方法和你的匿名函数

def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {

override def knownSize = self.knownSize

//调用父亲的hasNext

def hasNext = self.hasNext

//调用父亲的next

def next() = f(self.next())

}

2.4 什么时候开始执行这些迭代器呢?

//当咱们使用while循环用迭代器调用hasNext和next的时候方法才会执行

while (itStr02tToMap.hasNext) {

val tuple = itStr02tToMap.next()

println(tuple)

}

逻辑架构图:

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。