Scala深入学习之函数式编程
程序员文章站
2022-06-06 23:15:35
...
一、函数式编程
示例代码:
package matchDemo.function
/**
* @author : 蔡政洁
* @email :[email protected]
* @date : 2020/11/17
* @time : 6:25 下午
* scala函数式编程
*/
object FunctionOps1 {
def main(args: Array[String]): Unit = {
// 作为值的函数
funcOps1()
// 匿名函数
funcOps2()
// 高阶函数
funcOps3()
}
/*
函数可以作为值,传递给另外一个变量,或者另外一个函数
语法特点,必须要在函数后面加上空格或者下划线
*/
def funcOps1(): Unit ={
def sayGoodBye(name:String): Unit ={
println("good bye to:"+name)
}
sayGoodBye("jack")
// 传递给另外一个变量,用变量来调用
val sayBye = sayGoodBye _
sayBye("alex")
//传递给另外一个函数
def sayBeyBey = sayGoodBye _
sayBeyBey("lili")
}
/*
所谓匿名函数,其实就是没有名字的函数
Scala定义一个完整函数:
def funcName(params):returnType = {body}
Scala定义一个匿名函数:
(params) => {body} 匿名函数的实现
(params) => returnType 匿名函数的定义
问题是该匿名函数如何被调用
--> 只能将匿名函数赋值给另外一个变量或者函数来调用
*/
def funcOps2(): Unit ={
// 定义一个匿名函数,并赋值给一个变量
val sayBey = (name:String) => {
println("good bye to:"+name)
}
// 调用匿名函数
sayBey("alex")
def sayBeyBey = (name:String) => {
println("good bye to:"+name)
}
sayBeyBey("jone")
}
/*
所谓高阶函数:带函数参数的函数,一个函数的参数是函数,把这种函数称之为高阶函数(high level function)
*/
def funcOps3(): Unit ={
// 定义一个高阶函数
def sayBey(name:String,func:(String) => Unit): Unit ={
func(name)
}
// 调用函数sayBey
sayBey("alex",(name:String) => method(name))
// 传递匿名函数
sayBey("pony",(name:String) => println(name))
// 简化书写
// 如果匿名函数中只有一个变量,可以省略掉()
sayBey("cheery",name => println(name))
// 可以使用通配符"_"代替变量
sayBey("candy", println(_))
// 最简单可以连通配符"_"省略
sayBey("luzy", println)
// 重新在调用上述函数
sayBey("gucci",method)
}
def method(str:String): Unit ={
println("一日之计在于晨")
println(str)
println("一年之计在于春")
}
}
运行结果:
good bye to:jack
good bye to:alex
good bye to:lili
good bye to:alex
good bye to:jone
一日之计在于晨
alex
一年之计在于春
pony
cheery
candy
luzy
一日之计在于晨
gucci
一年之计在于春
二、高阶函数
示例代码:
package matchDemo.function
/**
* @author : 蔡政洁
* @email :[email protected]
* @date : 2020/11/18
* @time : 10:33 上午
* Scala中常见的高阶函数,这些高阶函数都是作用在集合上面
* filter
* map
* flatmap
* reduce
* foreach
* dropWhile
* sortWith
* groupBy
* partitionBy
*/
object FunctionOps2 {
def main(args: Array[String]): Unit = {
filterOps()
mapOps()
flatMapOps()
reduceOps()
dropWhileOps()
sortWithOps()
groupByOps()
partitionOps()
}
/*
filter:过滤
filter:(A => Boolean)
过滤掉集合中元素A,经过函数操作,返回值为false的元素
*/
def filterOps(): Unit ={
// 过滤掉集合中的偶数,留下集合中的奇数
val array = 1 to 10
var filtered = array.filter((num:Int) => num%2 != 0)
println(filtered.mkString("[",",","]"))
// 省略推断类型
filtered = array.filter((num) => num%2 != 0)
println(filtered.mkString("[",",","]"))
// 省略括号
filtered = array.filter(num => num%2 != 0)
println(filtered.mkString("[",",","]"))
// 使用通配符
filtered = array.filter(_ % 2 != 0)
println(filtered.mkString("[",",","]"))
}
/*
map:(p:A => B)
将一个集合中的所有元素A,都要作用在该匿名函数p上,每一个元素调用一次该匿名函数,将元素A最终转换成元素B
需要注意的是,A和B都是数据类型可以一致,也可以不一致
map操作其实就是一个one-2-one的映射操作
*/
def mapOps(): Unit ={
val array = 1 to 5
// 将集合中的每一个元素扩大1.5倍
var newArr:IndexedSeq[Double] = array.map((num:Int) => num*1.5)
println(newArr.mkString("[",",","]"))
// 省略推断类型
newArr = array.map((num) => num*1.5)
println(newArr.mkString("[",",","]"))
// 省略括号
newArr = array.map(num => num*1.5)
println(newArr.mkString("[",",","]"))
// 使用通配符
newArr = array.map(_ * 1.5)
println(newArr.mkString("[",",","]"))
}
/*
flatmap ---> (f:A => Iterable(B))
flatmap和map的操作,比较相似,不同之处在于作用于匿名函数的返回值类型不一样
map操作是one-2-one
flatmap操作是one-2-many,类似数据库中列转行的操作
----------------------------------------------------------
foreach(p:A => Unit)
遍历集合中每一个元素A,进行操作,返回值类型为Unit
*/
def flatMapOps(): Unit ={
val array = Array(
"i think there i am",
"you are a lucky dog",
"you are a green eye guy"
)
// 提取集合中的每一个单词
var words = array.flatMap((line:String) => line.split(" "))
// 查看集合word中的数据,遍历
for(word <- words){
print(word+" ")
}
println("\r\n-----------------")
// 省略推断类型
words = array.flatMap((line) => line.split(" "))
// 使用foreach遍历
words.foreach((word:String) => print(word + " "))
println("\r\n-----------------")
// 使用通配符
words = array.flatMap(_.split(" "))
// 使用foreach遍历
words.foreach((word:String) => println(word + " "))
}
/*
reduce(p:(A1,A2) => A3)
reduce是一个聚合函数,将2个A转换成1个A(其作用就是,作用在集合中的元素,进行聚合操作,得到一个新的值)
var sum = 0
for (i <- array){
sum = sum + i
}
此时,在每一次计算过程中的sum就是这里的A1,而i就是A2,sum和i聚合结束后的结果就是A3
此时的A3又作为下一次聚合操作中的sum,也就是A1
*/
def reduceOps(): Unit ={
val array = 1 to 6
var sum = 0
for (i <- array){
println(s"sum=${sum},i=${i}")
sum = sum + i
}
println("final sum is:"+sum)
println("-----------------------------")
sum = array.reduce((A1:Int,A2:Int) => {
println(s"sum=${A1},i=${A2}")
A1+A2
})
println("final sum is:"+sum)
println("-----------------------------")
sum = array.reduce((A1,A2) => {
A1+A2
})
println("final sum is:"+sum)
println("-----------------------------")
sum = array.reduce(_ + _) // 最简形式
println("final sum is:"+sum)
}
/*
dropWhile(p:A => Boolean)
该函数和filter一样,作用在集合的每一个元素,返回值为boolean类型
dropWhile删除元素,直到不满足条件位置
*/
def dropWhileOps(): Unit ={
val array = Array(3,-6,7,1,3,4,-8,2)
// 循环删除其中的偶数,直到条件不满足
var newArr = array.dropWhile((num:Int) => num%2 != 0)
println(newArr.mkString("[",",","]"))
}
/*
sortWith:排序操作
sortWith((A,A) => boolean)
返回值是boolean类型,同时sortWith是排序,显示就是要对这两个元素A进行大小比较,比较的结果就是boolean
*/
def sortWithOps(): Unit ={
val array = Array(3,-6,7,1,3,4,-8,2)
// 对集合中的元素进行升序排序
var newArr = array.sortWith((v1,v2) => v1<v2)
println(newArr.mkString("[",",","]"))
newArr = array.sortWith(_ > _)
println(newArr.mkString("[",",","]"))
}
/*
groupBy就是SQL中的group by
*/
def groupByOps(): Unit = {
val array = Array(
"广东,广州",
"广东,深圳",
"广东,珠海",
"浙江,杭州",
"江苏,南京",
"江苏,宿迁",
"江苏,苏州",
"湖北,武汉",
"福建,福州",
"江西,南昌",
"山东,济南",
"山东,青岛"
)
/*
按照省份,对每一个城市进行分组
用sql:
select province,city from xxx group by province;
*/
val province2Info:Map[String,Array[String]] = array.groupBy(line => line.substring(0,line.indexOf(",")))
for ((province,cities) <- province2Info){
println(s"province:${province}--->${cities.mkString("[",",","]")}")
}
println("------------grouped------------------")
// 将原来的集合进行分组,每个组内的元素有两个,或者可以理解为均分集合,每一份都是一个组
val arrays = array.grouped(2)
for (arr <- arrays){
println(arr.mkString("[",",","]"))
}
}
/*
将集合中的元素,按照一定的条件进行分组,最后分成两个组
partitionBy(p:A => boolean):(集合A,集合B)
在每一个元素A上进行作用该匿名函数,满足条件,共同构成返回值集合A, 不满足条件的共同构成返回值集合B
最后达到分区效果
*/
def partitionOps(): Unit ={
val array = Array(3,-6,7,1,3,4,-8,2)
// 将集合array,按照4进行分区,小于4的在一个分区中,大于等于4的在另一个分区
val (left,right) = array.partition((num:Int) => num <4)
println(left.mkString("[",",","]"))
println(right.mkString("[",",","]"))
}
}
运行结果:
[1,3,5,7,9]
[1,3,5,7,9]
[1,3,5,7,9]
[1,3,5,7,9]
[1.5,3.0,4.5,6.0,7.5]
[1.5,3.0,4.5,6.0,7.5]
[1.5,3.0,4.5,6.0,7.5]
[1.5,3.0,4.5,6.0,7.5]
i think there i am you are a lucky dog you are a green eye guy
-----------------
i think there i am you are a lucky dog you are a green eye guy
-----------------
i
think
there
i
am
you
are
a
lucky
dog
you
are
a
green
eye
guy
sum=0,i=1
sum=1,i=2
sum=3,i=3
sum=6,i=4
sum=10,i=5
sum=15,i=6
final sum is:21
-----------------------------
sum=1,i=2
sum=3,i=3
sum=6,i=4
sum=10,i=5
sum=15,i=6
final sum is:21
-----------------------------
final sum is:21
-----------------------------
final sum is:21
[-6,7,1,3,4,-8,2]
[-8,-6,1,2,3,3,4,7]
[7,4,3,3,2,1,-6,-8]
province:浙江--->[浙江,杭州]
province:广东--->[广东,广州,广东,深圳,广东,珠海]
province:江苏--->[江苏,南京,江苏,宿迁,江苏,苏州]
province:福建--->[福建,福州]
province:湖北--->[湖北,武汉]
province:江西--->[江西,南昌]
province:山东--->[山东,济南,山东,青岛]
------------grouped------------------
[广东,广州,广东,深圳]
[广东,珠海,浙江,杭州]
[江苏,南京,江苏,宿迁]
[江苏,苏州,湖北,武汉]
[福建,福州,江西,南昌]
[山东,济南,山东,青岛]
[3,-6,1,3,-8,2]
[7,4]
三、闭包和柯里化
示例代码:
package matchDemo.function
/**
* @author : 蔡政洁
* @email :[email protected]
* @date : 2020/11/18
* @time : 4:49 下午
* scala函数操作之
* 闭包
* 柯里化
*/
object FunctionOps3 {
def main(args: Array[String]): Unit = {
// 闭包
closureOps()
// 柯里化
curringOps()
}
def closureOps(): Unit ={
// 定义一个匿名函数,赋值给了一个有参的函数,匿名函数内部的实现需要前面定义的参数
def mulBy(factor:Double) = (x:Double) => factor * x
val triple = mulBy(3.0)
val half = mulBy(0.5)
/*
mulBy的函数体是通过一个匿名函数来实现的
而该匿名函数(x:Double) => factor * x,需要一个参数factor,并没有赋值,而该factor来自于前面的函数
程序的执行过程:
首先,在代码中定义了两个函数
第一个是mulBy
第二个是匿名函数(x:Double) => factor * x
其次,执行函数mulBy,并赋值给triple,这样,首先就将factor值赋值成3.0
函数执行完毕之后,是不是就进行弹栈,mulBy的实现匿名函数。
再其次,匿名函数(x:Double) => factor * x压栈,factor是不是就将刚才的3.0保存到自己的局部变量中
最后,调用它的triple(42)的时候,42传递给了x,最终结果就是42 * 3 = 126
在这个过程中,最后,匿名函数调用了一个不再其作用于范围内的变量factor,先弹栈,然后将factor保存到了
匿名函数,最后在匿名函数中调用了factor。
把这种结构称之为闭包——函数可以在变量不处于其作用域范围内被调用。
*/
println(triple(42) + "-------" + half(42))
}
/*
柯里化:
原来的函数有两个参数,def sum(x:Int,y:Int) = x+y
现在将sum函数进行改变,只保留其中一个参数,另外一个参数作为一个新的匿名函数的参数列表而存在
通常该sum函数的函数体就是该匿名函数
把这个过程称之为柯里化
一个很重要的操作就是降维,降低参数的个数,维度
*/
def curringOps(): Unit ={
def sum(x:Int,y:Int) = x+y
// 进行柯里化改造
def total(x:Int) = (y:Int) => x+y
println(total(3)(4))
}
}
运行结果:
126.0-------21.0
7
以上内容仅供参考学习,如有侵权请联系我删除!
如果这篇文章对您有帮助,左下角的大拇指就是对博主最大的鼓励。
您的鼓励就是博主最大的动力!
上一篇: Vue学习笔记(一) 入门