大数据技术之_16_Scala学习_09_函数式编程-高级
第十三章 函数式编程-高级13.1 偏函数(partial function)13.1.1 提出一个需求,引出思考13.1.2 解决方式-filter + map 返回新的集合13.1.3 解决方式-模式匹配13.1.4 偏函数的基本介绍13.1.5 偏函数的快速入门13.1.6 偏函数的小结13.1.7 偏函数的简写形式13.2 作为参数的函数13.3 匿名函数13.4 高阶函数(higher-order function)13.5 参数(类型)推断13.6 闭包(closure)13.7 函数柯里化(curry)13.8 控制抽象函数
第十三章 函数式编程-高级
13.1 偏函数(partial function)
13.1.1 提出一个需求,引出思考
给你一个集合 val list = List(1, 2, 3, 4, "abc"),请完成如下要求:
1、将集合 list 中的所有数字 +1,并返回一个新的集合。
2、要求忽略掉 非数字 的元素,即返回的 新的集合 形式为 (2, 3, 4, 5)。
13.1.2 解决方式-filter + map 返回新的集合
13.1.3 解决方式-模式匹配
两种方式的示例代码如下:
示例代码如下:
package com.atguigu.chapter13
/**
* 给你一个集合 val list = List(1, 2, 3, 4, "abc"),请完成如下要求:
* 1、将集合 list 中的所有数字 +1,并返回一个新的集合。
* 2、要求忽略掉 非数字 的元素,即返回的 新的集合 形式为 (2, 3, 4, 5)。
*/
object PartialFunDemo01 {
def main(args: Array[String]): Unit = {
// 思路1:filter + map 方式解决
// 虽然可以解决问题,但是麻烦。
val list = List(1, 2, 3, 4, "abc")
// 先过滤,再map
list.filter(f1)
println(list.filter(f1).map(f2).map(f3)) // List(2, 3, 4, 5)
// 思路2:模式匹配
// 小结:虽然使用模式匹配比较简单,但是不够完美。
val list2 = list.map(addOne2)
println(list2) // List(2, 3, 4, 5, ())
}
// 模式匹配
def addOne2(i: Any): Any = {
i match {
case x:Int => x + 1
case _ =>
}
}
// 将 List 转为 Any
def f1(n: Any): Boolean = {
n.isInstanceOf[Int]
}
// 将 Any 转为 Int [map]
def f2(n: Any): Int = {
n.asInstanceOf[Int]
}
def f3(n: Int): Int = {
n + 1
}
}
输出结果如下:
List(2, 3, 4, 5)
List(2, 3, 4, 5, ())
13.1.4 偏函数的基本介绍
13.1.5 偏函数的快速入门
示例代码如下:
package com.atguigu.chapter13
object PartialFunDemo02 {
def main(args: Array[String]): Unit = {
// 使用偏函数解决
val list = List(1, 2, 3, 4, "hello")
// 定义一个偏函数
// 1. PartialFunction[Any, Int] 表示偏函数接收的参数类型是 Any,返回的类型是 Int
// 2. isDefinedAt(x: Any) 如果返回 true,就会去调用 apply 构建对象实例,如果是 false,就过滤
// 3. apply 构造器,对传入的值 + 1,并返回(新的集合)
val addOne3 = new PartialFunction[Any, Int] {
def isDefinedAt(any: Any) = if (any.isInstanceOf[Int]) true else false
def apply(any: Any) = any.asInstanceOf[Int] + 1 // 将 any 显示转换成 Int
}
// 使用偏函数
// 说明:如果是使用偏函数,则不能使用 map,应该使用 collect
// 说明偏函数的执行流程
// 1. 遍历 list 集合的所有元素
// 2. 然后调用 val element = if(partialFun-isDefinedAt(list单个元素)) {partialFun-apply(list单个元素)}
// 3. 每得到一个符合要求的元素 element,放入到新的集合,最后返回
val list3 = list.collect(addOne3)
println(list3) // List(2, 3, 4, 5)
}
}
输出结果如下:
List(2, 3, 4, 5)
13.1.6 偏函数的小结
13.1.7 偏函数的简写形式
示例代码如下:
package com.atguigu.chapter13
/**
* 偏函数简化形式
*/
object PartialFunDemo03 {
def main(args: Array[String]): Unit = {
// 使用偏函数的简化形式解决
// 第一种简写形式:
def f2: PartialFunction[Any, Int] = {
case i: Int => i + 1 // case 语句可以自动转换为偏函数
case j: Double => (j * 2).toInt
}
val list2 = List(1, 2, 3, 4, 5.6, "hello").collect(f2)
println(list2) // List(2, 3, 4, 5, 11)
// 第二种简写形式:
val list3 = List(1, 2, 3, 4, "ABC").collect { case i: Int => i + 1 }
println(list3) // List(2, 3, 4, 5)
}
}
输出结果如下:
List(2, 3, 4, 5, 11)
List(2, 3, 4, 5)
13.2 作为参数的函数
1、基本介绍
2、快速入门案例
示例代码如下:
package com.atguigu.chapter13
object FunParameterDemo01 {
def main(args: Array[String]): Unit = {
def plus(x: Int) = 3 + x
val result1 = Array(1, 2, 3, 4).map(plus(_))
println(result1.mkString(",")) // (4,5,6,7)
// 1. 在 scala 中,函数也是有类型,比如 plus 就是 <function1>
println("puls的函数类型是" + (plus _))
}
}
输出结果如下:
4,5,6,7
puls的函数类型是<function1>
3、应用案例小结
13.3 匿名函数
1、基本介绍
2、快速入门案例
示例代码如下:
package com.atguigu.chapter13
object AnonymouseFunctionDemo01 {
def main(args: Array[String]): Unit = {
// 对匿名函数的说明
// 1. 不需要写 def 函数名
// 2. 不需要写返回类型,使用类型推导
// 3. = 变成 =>
// 4. 如果有多行,则使用 {} 包括
val triple = (x: Double) => 3 * x
println(triple) // <function1>
println(triple(3)) // 9.0
}
}
输出结果如下:
<function1>
9.0
3、练习题
请编写一个匿名函数,可以返回2个整数的和,并输出该匿名函数的类型。
示例代码如下:
val f1 = (n1: Int, n2: Int ) => {
println("匿名函数被调用")
n1 + n2
}
println("f1类型=" + f1) // f1类型=<function2>
println(f1(10, 30)) // 40
13.4 高阶函数(higher-order function)
1、基本介绍
能够接受函数作为参数的函数,叫做高阶函数 (higher-order function)。可使应用程序更加健壮。
2、高阶函数基本使用案例
扩展代码如下:
package com.atguigu.chapter13
object HigherOrderFunctionDemo01 {
def main(args: Array[String]): Unit = {
// test 就是一个高阶函数,它可以接收 f: Double => Double 和 f1: Double => Int
def test(f: Double => Double, f1: Double => Int, n1: Double) = {
f(f1(n1))
}
// sum 是接收一个 Double,返回一个 Double
def sum(d: Double): Double = {
d + d
}
def mod(d: Double): Int = {
d.toInt % 2
}
val res = test(sum, mod, 5.0)
println("res=" + res) // 2.0
}
}
输出结果如下:
res=2.0
3、高阶函数可以返回函数类型
示例代码如下:
package com.atguigu.chapter13
object HigherOrderFunctionDemo02 {
def main(args: Array[String]): Unit = {
// 说明
// 1. minusxy 是高阶函数,因为它返回匿名函数
// 2. 返回的匿名函数是 (y: Int) => x - y
// 3. 返回的匿名函数可以使用变量接收
def minusxy(x: Int) = {
(y: Int) => x - y // 匿名函数
}
// 分步执行
// f1 就是 (y: Int) => 3 - y
val f1 = minusxy(3)
println("f1的类型=" + f1)
println(f1(1)) // 2
println(f1(9)) // -6
// 也可以一步到位的调用(函数柯里化)
println(minusxy(4)(9)) // -5
}
}
输出结果如下:
f1的类型=<function1>
2
-6
-5
13.5 参数(类型)推断
1、基本介绍
2、应用案例
示例代码如下:
package com.atguigu.chapter13
object ParameterInferDemo01 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4)
println(list.map((x: Int) => x + 1)) // (2,3,4,5)
println(list.map((x) => x + 1)) // (2,3,4,5) 参数类型是可以推断时,可以省略参数类型。
println(list.map(x => x + 1)) // (2,3,4,5) 当传入的函数,只有单个参数时,可以省去括号。
println(list.map(_ + 1)) // (2,3,4,5) 如果变量只在=>右边只出现一次,可以用_来代替。
println(list.reduce(f1)) // 10
println(list.reduce((n1: Int, n2: Int) => n1 + n2)) // 10
println(list.reduce((n1, n2) => n1 + n2)) // 10
println(list.reduce(_ + _)) // 10
}
def f1(n1: Int, n2: Int): Int = {
n1 + n2
}
}
输出结果如下:
List(2, 3, 4, 5)
List(2, 3, 4, 5)
List(2, 3, 4, 5)
List(2, 3, 4, 5)
10
10
10
10
3、应用案例小结
13.6 闭包(closure)
1、基本介绍
2、应用案例小结
3、闭包的最佳实践
示例代码如下:
package com.atguigu.chapter13
/**
* 请编写一个程序,具体要求如下:
* 编写一个函数 makeSuffix(suffix: String) 可以接收一个文件后缀名(比如.jpg),并返回一个闭包
* 调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg),则返回 文件名.jpg,如果已经有.jpg后缀,则返回原文件名。
* 要求使用闭包的方式完成。
* String.endsWith(xx)
*/
object ClosureDemo01 {
def main(args: Array[String]): Unit = {
// 使用并测试
val f = makeSuffix(".jpg")
println(f("dog.jpg")) // dog.jpg
println(f("cat")) // cat.jpg
}
// 自定义的函数
def makeSuffix(suffix: String) = {
// 返回一个匿名函数,该匿名函数会使用外部函数的suffix,那么该函数和suffix整体形成一个闭包。
(filename: String) => {
if (filename.endsWith(suffix)) {
filename
} else {
filename + suffix
}
}
}
}
输出结果如下:
dog.jpg
cat.jpg
4、闭包的好处
13.7 函数柯里化(curry)
1、基本介绍
2、函数柯里化快速入门案例
3、函数柯里化最佳实践
示例代码如下:
package com.atguigu.chapter13
/**
* 函数柯里化最佳实践
* 比较两个字符串在忽略大小写的情况下是否相等,注意,这里是两个任务:
* 全部转大写(或小写)
* 比较是否相等
* 针对这两个操作,我们用一个函数去处理的思想,其实也变成了两个函数处理的思想(柯里化)
*/
object CurryDemo02 {
def main(args: Array[String]): Unit = {
// 方式1:简单的方式,使用一个函数完成
def eq(s1: String)(s2: String): Boolean = {
s1.toLowerCase == s2.toLowerCase
}
println(eq("hello")("HELLO"))
// 方式2:使用稍微高级的用法(隐式类):形式为 str.方法()
def eq2(s1: String, s2: String): Boolean = {
s1.equals(s2)
}
// 隐式类:该隐式类扩展了String对象的功能
implicit class TestEq(s: String) {
// 体现了将比较字符串的事情,分解成两个任务完成:
// 任务1:checkEq 完转换大小写
// 任务2.:f函数完成比较任务
def checkEq(ss: String)(f: (String, String) => Boolean): Boolean = {
f(s.toLowerCase, ss.toLowerCase)
}
}
val str1 = "hello"
println(str1.checkEq("HeLLO")(eq2))
// 方式2的简化写法
str1.checkEq("HeLLO")((s1: String, s2: String) => { s1.equals(s2) })
str1.checkEq("HeLLO")((s1: String, s2: String) => s1.equals(s2)) // 代码块只有一行代码时。可以省略{}
str1.checkEq("HeLLO")((s1, s2) => s1.equals(s2)) // 参数类型是可以推断时,可以省略参数类型。
str1.checkEq("HeLLO")(_.equals(_)) // 如果变量只在=>右边只出现一次,可以用_来代替。
}
}
输出结果如下:
true
true
13.8 控制抽象函数
1、看一个需求
2、控制抽象基本介绍
3、快速入门案例
示例代码如下:
package com.atguigu.chapter13
object AbstractControlDemo01 {
def main(args: Array[String]): Unit = {
// myRunInThread 就是一个抽象控制函数,其参数是没有输入,也没有输出的函数 f1: () => Unit
def myRunInThread(f1: () => Unit) = {
new Thread {
override def run(): Unit = {
f1()
}
}.start()
}
myRunInThread {
() =>
println("干活咯!5秒完成...")
Thread.sleep(5000)
println("干完咯!")
}
// 简写形式
def myRunInThread2(f1: => Unit) = {
new Thread {
override def run(): Unit = {
f1
}
}.start()
}
// 对于没有输入,也没有返回值函数,可以简写成如下形式:
myRunInThread2 {
println("干活咯!5秒完成...~~~")
Thread.sleep(5000)
println("干完咯!~~~")
}
}
}
4、进阶用法:实现类似 while 的 mywhile 函数
示例代码如下:
package com.atguigu.chapter13
object AbstractControlDemo02 {
def main(args: Array[String]): Unit = {
var x = 10
while (x > 0) {
x -= 1
println("x=" + x)
}
// 说明:实现类似 while 的 mywhile 函数
// 1 函数名为 mywhile,实现了类似 while 循环的效果
// 2. condition: => Boolean 是一个没有输入值,返回 Boolean 类型函数
// 3. block: => Unit 没有输入值,也没有返回值的函数
def mywhile(condition: => Boolean)(block: => Unit): Unit = {
// 类似 while 循环,递归
if (condition) {
block // x=9 x=8 x=7 ...
mywhile(condition)(block)
}
}
x = 10
mywhile(x > 0) {
x -= 1
println("x=" + x)
}
}
}
输出结果如下:
x=9
x=8
x=7
x=6
x=5
x=4
x=3
x=2
x=1
x=0
-----
x=9
x=8
x=7
x=6
x=5
x=4
x=3
x=2
x=1
x=0
大数据技术之_16_Scala学习_09_函数式编程-高级的更多相关文章
- 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础
第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...
- 大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值
第八章 面向对象编程-高级8.1 静态属性和静态方法8.1.1 静态属性-提出问题8.1.2 基本介绍8.1.3 伴生对象的快速入门8.1.4 伴生对象的小结8.1.5 最佳实践-使用伴生对象解决小孩 ...
- 大数据技术之_16_Scala学习_05_面向对象编程-中级
第七章 面向对象编程-中级7.1 包7.1.1 Java 中的包7.1.2 Scala 中的包7.1.3 Scala 包的特点概述7.1.4 Scala 包的命名7.1.5 Scala 会自动引入的常 ...
- 大数据技术之_16_Scala学习_01_Scala 语言概述
第一章 Scala 语言概述1.1 why is Scala 语言?1.2 Scala 语言诞生小故事1.3 Scala 和 Java 以及 jvm 的关系分析图1.4 Scala 语言的特点1.5 ...
- 大数据技术之_16_Scala学习_08_数据结构(下)-集合操作+模式匹配
第十一章 数据结构(下)-集合操作11.1 集合元素的映射-map11.1.1 map 映射函数的操作11.1.2 高阶函数基本使用案例1+案例211.1.3 使用 map 映射函数来解决11.1.4 ...
- 大数据技术之_16_Scala学习_02_变量
第二章 变量2.1 变量是程序的基本组成单位2.2 Scala 变量的介绍2.2.1 概念2.2.2 Scala 变量使用的基本步骤2.3 Scala 变量的基本使用2.4 Scala 变量使用说明2 ...
- 大数据技术之_16_Scala学习_07_数据结构(上)-集合
第十章 数据结构(上)-集合10.1 数据结构特点10.1.1 Scala 集合基本介绍10.1.2 可变集合和不可变集合举例10.2 Scala 不可变集合继承层次一览图10.2.1 图10.2.2 ...
- 大数据技术之_16_Scala学习_13_Scala语言的数据结构和算法_Scala学习之旅收官之作
第十九章 Scala语言的数据结构和算法19.1 数据结构(算法)的介绍19.2 看几个实际编程中遇到的问题19.2.1 一个五子棋程序19.2.2 约瑟夫问题(丢手帕问题)19.2.3 其它常见算法 ...
- 大数据技术之_09_Flume学习_Flume概述+Flume快速入门+Flume企业开发案例+Flume监控之Ganglia+Flume高级之自定义MySQLSource+Flume企业真实面试题(重点)
第1章 Flume概述1.1 Flume定义1.2 Flume组成架构1.2.1 Agent1.2.2 Source1.2.3 Channel1.2.4 Sink1.2.5 Event1.3 Flum ...
随机推荐
- 22、(转载)jQueryMobile 知识点总结
本文转自:http://www.cnblogs.com/jxyedu HTML5技术生态介绍 H5的现状与未来 HTML5是用于取代1999年所制定的 HTML 4.01 和 XHTML 1.0 标准 ...
- Python 3基础教程1-环境安装和运行环境
本系列开始介绍Python3的基础教程,为什么要选中Python 3呢?之前呢,学Python 2,看过笨方法学Python,学了不到一个礼拜,就开始用Python写Selenium脚本.最近看到一些 ...
- nginx 快速查看配置文件的方法
查看nginx实际调用的配置文件 1.查看nginx路径 ps aux|grep nginx root ?? S :43上午 :00.08 nginx: worker process root ?? ...
- Oz 创建CentOS6镜像
参考 http://linuxblind.blog.51cto.com/7616603/1655550/ http://www.chenshake.com/oz-making-centos-mirro ...
- SPOJ 364 Pocket Money 简单DP
跟矩阵链乘同类型的题…… 输出用%llu不是%I64u…… 几组数据: 141+2*4+3*4+5*00*5*6+7*3+23+0+6+7+0+44*5+7*1*1+12*0+3*4*0+5*6+7+ ...
- Codeforces Round #326(Div2)
CodeForces 588A 题意:Duff喜欢吃肉,想在接下来的n天,每天都有Ai斤肉吃,但每一天肉的单价Pi不定,肉 可以保存不过期,现已知n天每天肉的斤数Ai,以及单价Pi,为了使每天都 ...
- linux configuration
sudo vi /etc/profile export JAVA_HOME=/usr/bin/jdk1.8.0_40export JRE_HOME=${JAVA_HOME}/jre export C ...
- Spring Cloud Config 搭建Config 服务
配置中心: open API 配置生效监控 一致性的K-V存储 统一配置的实时推送 配置全局恢复.备份.历史版本 高可用集群 通过config 获取配置,流程: 下面介绍,基于spring cloud ...
- Android记事本开发03
昨天: 生成签名文件及导出apk 遇到的问题: 无. 今天: activity和intent基础
- [codeforces] 498D Traffic Jams in th Land
原题 简单的线段树问题. 对于题目中,a[i]的范围是2~6,我们仔细思考可以得出第0秒和第60秒是一样的(因为2~6的最小公倍数是60,),然后我们可以建一个线段树,里面记录0~59秒时刻开始通过这 ...