美文网首页
Spark编程基础(Scala版)——Scala函数编程

Spark编程基础(Scala版)——Scala函数编程

作者: kaiker | 来源:发表于2021-08-07 15:14 被阅读0次

    函数内部对外部的全局状态没有任何影响,即函数的调用结果只与输入值有关,不影响全局数据

    在纯函数编程中,变量是不可变的,即函数的使用方式和其他数据类型的使用方式完全一致,可以将函数赋值给变量

    1、函数的定义与使用

    函数也应该有类型和值的区分(就像int i = 0有类型int和值0)

    类型需要明确函数接收多少参数、每个参数的类型以及返回的值

    值就是函数的具体实现

    val counter: (Int) => Int = { value => value + 1 }

    • (Int) => Int就是类型
    • { value => value + 1 }就是值, => 前是参数名,后是具体的运算语句或表达式
    • 也可以简写成 val counter = (value:Int)=> value + 1 因为类型是可以根据运算推断的
    • 几个简写的例子
    val counter = (_:Int) + 1 //有类型时括号不能省略,等效于“x:Int=>x+1”
    val add = (_:Int) + (_:Int) //等效于“(a:Int,b:Int)=>a+b”
    val m2=m1.map(_*2)//map接受一个函数作为参数,相当于“m1.map(x=>x*2)”,参数的类型可以根据m1的元素类型推断出
    

    2、高阶函数

    函数可以作为其他函数的参数或返回值。

    当一个函数包含其他函数作为其参数或者返回结果为一个函数时,该函数被称为高阶函数

    def sum(f: Int => Int, a: Int, b: Int):Int = {
        if(a > b) 0 else f(a) + sum(f, a+1, b)
    }
    
    sum(x=>x,1,5)
    sum(x=>x*x,1,5)
    

    3、闭包

    当函数的执行依赖于申明在函数外部的一个或多个变量时,称这个函数为闭包

    var more = 10
    val addMore =(x:Int)=> x + more
    
    var sum=0
    val accumulator = (x:Int)=>sum+=x
    

    4、偏应用函数

    • 有时候函数参数可能始终取相同的值,为了避免每次都提供这些相同的值
    val a=sum(1,_:Int,_:Int) //只保留了sum的后两个参数
    

    5、针对容器的操作

    遍历操作

    • 标准的遍历方法为foreach
    • 接收一个函数操作,类型为Elem,返回结果为U
      def foreach[U](f: Elem => U) :Unit
    scala> val list = List(1, 2, 3)
    list: List[Int] = List(1, 2, 3)
    scala> val f=(i:Int)=>println(i)
    f: Int => Unit = <function1>
    scala> list.foreach(f)
    
    scala> val university = Map("XMU" ->"Xiamen University", "THU" ->"Tsinghua University","PKU"->"Peking University")
    university: scala.collection.mutable.Map[String,String] = ...
    scala> university foreach{kv => println(kv._1+":"+kv._2)} // 二元组的元素可以_1, _2这样调用
    

    映射操作map和flatMap

    • 最常见的操作是map和flatMap
    • map方法是将函数应用到集合中的每个元素,映射得到一个新的元素,map映射的结果会返回一个与原容器类型大小相同的新容器,只不过元素的类型可能不同
        scala> val books =List("Hadoop","Hive","HDFS")
        books: List[String] = List(Hadoop, Hive, HDFS)
        scala> books.map(s => s.toUpperCase)
        //toUpperCase方法将一个字符串中的每个字母都变成大写字母
        res56: List[String] = List(HADOOP, HIVE, HDFS)
        scala> books.map(s => s.length) //将字符串映射到它的长度
        res57: List[Int] = List(6, 4, 4) //新列表的元素类型为Int
    
    • flatMap将某个函数应用到每个元素时,会先拍扁合并,然后再进行操作
        scala> books flatMap (s => s.toList)
        res58: List[Char] = List(H, a, d, o, o, p, H, i, v, e, H, D, F, S)
    

    过滤操作

    • filter 接受一个返回布尔值的函数f作为参数,并将f作用到每个元素上,将f返回真值的元素组成一个新的容器返回
      val l=List(1,2,3,4,5,6) filter {x => x%2==0}

    规约操作

    • 对容器元素进行两两运算,将其规约为一个值

    reduce

    • reduce接受一个二元函数f作为参数,首先将f作用在某两个元素上并返回一个值,然后再将f作用在上一个返回值和容器的下一个元素上,在返回一个值
    scala> val s1=Set(1,2,3)
    s1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
    scala> val s2 = util.Random.shuffle(s1) //打乱集合的顺序生成一个新集合
    s2: scala.collection.immutable.Set[Int] = Set(3, 2, 1)
    scala> s1==s2 //s1和s2只是元素顺序不一样,但从集合的角度是完全相等的
    res18: Boolean = true
    scala> s1.reduce(_+_) //加法操作满足结合律和交换率,所以结果与遍历顺序无关
    

    fold

    • fold方法,可以传一个初始值,然后再接受一个与reduce中一样的二元函数参数
    scala> val list =List(1,2,3,4,5)
    list: List[Int] = List(1, 2, 3, 4, 5)
    scala> list.fold(10)(_*_)  // 10*1*2*3*4*5
    res32: Int = 1200
    

    拆分操作

    partition

    • partition方法接收一个布尔函数,用该函数对容器元素进行遍历,以二元组的形式返回满足条件和不满足条件的两个C[T]类型的集合
    scala> val xs = List(1,2,3,4,5)
    xs: List[Int] = List(1, 2, 3, 4, 5)
    scala> val part = xs.partition(_<3)
    part: (List[Int], List[Int]) = (List(1, 2),List(3, 4, 5))
    

    groupBy

    • groupBy接受一个返回U类型的函数,用该函数对容器元素进行遍历,将返回值相同的元素作为一个子容器,并与该相同的值构成一个键值对,最后返回的是一个类型为Map<U, C[T]>的映射
    scala> val gby = xs.groupBy(x=>x%3) //按被3整除的余数进行划分
    gby: scala.collection.immutable.Map[Int,List[Int]] = Map(2 -> List(2, 5), 1 -> List(1, 4), 0 -> List(3))
    

    grouped和sliding

    • 接受一个整形参数n,都将容器拆分为类型相同的子容器,并返回由这些子容器构成的迭代器
    • grouped从左到右划分多个大小为n的容器
    • sliding使用长度为n的滑动窗口,从左到右将容器截取为多个大小为n的子容器
    scala> val sl = xs.sliding(3)//滑动拆分为大小为3个子容器
    sl: Iterator[List[Int]] = non-empty iterator
    scala> sl.next //第一个子容器
    res7: List[Int] = List(1, 2, 3)
    scala> sl.next //第二个子容器
    res8: List[Int] = List(2, 3, 4)
    

    相关文章

      网友评论

          本文标题:Spark编程基础(Scala版)——Scala函数编程

          本文链接:https://www.haomeiwen.com/subject/xvowvltx.html