开发者学堂课程【Scala 核心编程 - 进阶:温故知新】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/610/detail/9075
温故知新
内容介绍:
一、map 映射回顾
二、filter 回顾
三、化简、折叠和扫描
四、扩展知识回顾
一、map 映射回顾
首先讲解了map映射操作,map不是集合中的map,而是一个函数map。
那么map映射是完成什么或者什么时候用到map映射呢?
有一些集合其中数组的元素每一个都需要进行处理,以前传统的方法使用一个函数接受这个集合:
例如学习java时是写一个函数,拿到该函数后,在函数中对集合进行遍历操作。
但是map映射不同,它是反过来给map再传入一个处理函数。在之前讲解map映射函数机制时写过一段模拟代码简单的演示了一下:
class MyList {
val list1 =List(3,5,7,9)
//新的集合
var list2 = List[Int]()
//写map
def map(f: Int=>Int): List[Int]={
//遍历集合
for (item <_this.list1) {
//过滤,扁平化。。。
list2 = list2 :+ f(item)
}
list2
}
假如有一个对象,其中有一个 map,map 会接收一个函数,该函数可以支持泛型,不一定为 int。
它在底层会将 list 进行遍历,遍历过程中会将遍历出的每一个元素进行处理,处理时就使用到传入的函数,处理完后就将结果放到一个新的集合中然后返回一个新的集合,这就是它的基本原理。
二、filter 回顾
map 映射讲解完后接着讲解了 filter。Filter 具体是传入一个过滤的函数,过滤函数不能随便写,必须要返回一个boolean类型。
例如部分代码:
val names = List("Alice","Bob"", "Nick")
val names2 =names.filter(startA)
println("names=" + names)
println("names2="+ names2)
}
def startA(str:String): Boolean = {
str.startsWith("A")
因为在底层调用函数 filter 会遍历 name 中的元素,将遍历出的每个元素放到startA,如果 startA 返回 true,就将遍历的元素放到新的集合中。
所以 map 和 filter 可以结合使用,比如先对集合进行一个映射,再对 filter 进行操作,
再进行一个折叠的操作:
names.map(函数).filter(xx).foldLeft()
这种方式处理力度更大,处理的不再是一个单位,而是一整个集合,使用比较多。
三、化简、折叠和扫描
之后我们讲解了化简、折叠和扫描。
化简是将二元函数引用于集合中的函数,经典案例是用化简的方式来求和:
package com.atguigu.chapter11
object ReduceDemo01 {
def main(args: Array[String]): Unit = {
/*
使用化简的方式来计算list集合的和
*/
val list = List(1,20,30,4,5)
val res = list.reduceLeft(sum)
//执行的流程分析
//步骤1(1+20)//步骤2(1+20)+30/步骤3((1+ 20)+ 30)+4
reduce分为三种:
reduce/reduceLeft/reduceRight,我们需要明白左化简是从左边开始运算,然后将得到的结果作为值传入给下一次运算的第一个参数。右化简是从右边开始运行,会把运算的结果作为下一次调用化简的里面函数的第二个参数。
在化简基础上我们讲解了折叠:
折叠与化简相似,但是折叠需要指定第一个或者最后一个元素,折叠时结果可以按照运算的规则将所有结果放在第一个或者最后一个元素中。
扫描最大的区别也是做折叠,但是会把产生的所有中间结果放置在一个集合中保存。
四、扩展知识回顾
上述讲完后我们继续学习了一些扩展知识(拉链、迭代器、流、视图、并行集合、操作符)和综合案例
视图在什么应用场景可以应用呢?
我们做一些大数据量的运算但不一定马上使用这个结果而是等待用户行为来出发,比如我们现在要运用一千万的数据给不同的用户,而不确定用户是否现在需要,用户用时会做一个动作才会去看,这时就可以用view的方式来进行优化,此时会对整个服务器的运算力会有一定的保存。
并行集合主要是使用多核CPU,提高并行运算的能力。实现的方式很简单,只需要在集合中先加入一个parallel再进行操作
(1 to 5).foreach(println(_))
println()
(1 to 5).par.foreach(println(_))
并行讲完后讲了操作符,重点有中置、后置、前置、赋值操作符。
接着我们讲解了模式匹配中的match,类似于java中的switch,但是功能更丰富。
因为它支持很多形式的匹配方式,比如得到的变量、匹配类型、匹配数组、匹配列表、匹配元组等,用这种方式可以快速实现一些功能。
模式匹配中的守卫类似于将模式匹配的一些具体值扩展成我们可以对一个范围进行匹配,
例如下面案例:
//表示忽略传入的ch
case _ if ch.toString.equals("3")=> digit = 3
case_if (ch > 1110|| ch < 120)=> println("ch > 10")
case _=> sign = 2
首先先写一个下划线,下划线表示忽略传入的ch,后面我们写上条件,如果条件满足,就可以执行后面的代码,所以说明match既可以匹配单个字符,也可以匹配一个范围内的字符。
后面讲到类型匹配和匹配数组,匹配数组留了一个练习:
val result = arr match {
//case Array(0) =>"0"
case Array(x, y) => ArrayBuffer(y,x) //? ArrayB(y,x)
//case Array(0,_*)=>"以0开头和数组"
case _ =>"不处理~~"
}
if (result.isInstanceOf[ArrayBuffer]){
println(result.asInstanceOf(ArrayBuffer])
}
这里有两种方式,如果是返回一个buffer,那么直接打印就可以看到该结果,如果是array,加上tobuffer即可。
val arrs2 = Array(Array(0),Array(1,0),Array(0,1,0),
Array(1,1,0),Array(1,1,0,1))
for (arr <- arrs2 ) {
val result = arr match {
// case Array (0) => "0"
case Array(x,y) => ArrayBuffer(y,x)/ / Array(y,x).toBuffer / / ? ArrayB(y,x)
//case Array (0,_*) =>“以0开头和数组”
case _ =>“不处理~~”
}
println("res=" + result) //ArrayBuffer(0,1)
}
运行结果就已经拿到了(0,1),如果什么都不处理可以返回一个空。如果就想返回一个 array,那么就可以 tobuffer 一下。