欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

以上内容仅供参考学习,如有侵权请联系我删除!
如果这篇文章对您有帮助,左下角的大拇指就是对博主最大的鼓励。
您的鼓励就是博主最大的动力!

相关标签: Scala学习指南