日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Scala入门到精通——第十三节 高阶函数

發布時間:2024/1/23 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala入门到精通——第十三节 高阶函数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本節主要內容

  • 高階函數簡介
  • Scala中的常用高階函數
  • SAM轉換
  • 函數柯里化
  • 部分應用函數
  • 1. 高階函數簡介

    高階函數主要有兩種:一種是將一個函數當做另外一個函數的參數(即函數參數);另外一種是返回值是函數的函數。這兩種在本教程的第五節 函數與閉包中已經有所涉及,這里簡單地回顧一下:
    (1)函數參數

    //函數參數,即傳入另一個函數的參數是函數 //((Int)=>String)=>String scala> def convertIntToString(f:(Int)=>String)=f(4) convertIntToString: (f: Int => String)Stringscala> convertIntToString((x:Int)=>x+" s") res32: String = 4 s
    • 1

    (2)返回值是函數的函數

    //高階函數可以產生新的函數,即我們講的函數返回值是一個函數 //(Double)=>((Double)=>Double) scala> def multiplyBy(factor:Double)=(x:Double)=>factor*x multiplyBy: (factor: Double)Double => Doublescala> val x=multiplyBy(10) x: Double => Double = <function1>scala> x(50) res33: Double = 500.0

    Scala中的高階函數可以說是無處不在,這點可以在scala中的API文檔中得到驗證,下圖給出的是Array數組的需要函數作為參數的API:

    例如flatMap方法,下面是其API的詳細內容:

    def flatMap[B](f: (A) ? GenTraversableOnce[B]): Array[B] [use case] Builds a new collection by applying a function to all elements of this array and using the elements of the resulting collections.//下面的代碼給出了該函數的用法 For example:def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+") The type of the resulting collection is guided by the static type of array. This might cause unexpected results sometimes. For example:// lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet)// lettersOf will return a Set[Char], not a Seq def lettersOf(words: Seq[String]) = words.toSet flatMap (word => word.toSeq)// xs will be a an Iterable[Int] val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2)// ys will be a Map[Int, Int] val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2) //下面幾行對該函數的參數進行了說明 B the element type of the returned collection. //指明f是函數,該函數傳入的參數類型是A,返回類型是GenTraversableOnce[B] f the function to apply to each element. returns a new array resulting from applying the given collection-valued function f to each element of this array and concatenating the results.
    • 1

    2. Scala中的常用高階函數

    1 map函數
    所有集合類型都存在map函數,例如Array的map函數的API具有如下形式:

    def map[B](f: (A) ? B): Array[B] 用途:Builds a new collection by applying a function to all elements of this array. B的含義:the element type of the returned collection. f的含義:the function to apply to each element. 返回:a new array resulting from applying the given function f to each element of this array and collecting the results. //這里面采用的是匿名函數的形式,字符串*n得到的是重復的n個字符串,這是scala中String操作的一個特點 scala> Array("spark","hive","hadoop").map((x:String)=>x*2) res3: Array[String] = Array(sparkspark, hivehive, hadoophadoop)//在函數與閉包那一小節,我們提到,上面的代碼還可以簡化 //省略匿名函數參數類型 scala> Array("spark","hive","hadoop").map((x)=>x*2) res4: Array[String] = Array(sparkspark, hivehive, hadoophadoop)//單個參數,還可以省去括號 scala> Array("spark","hive","hadoop").map(x=>x*2) res5: Array[String] = Array(sparkspark, hivehive, hadoophadoop)//參數在右邊只出現一次的話,還可以用占位符的表示方式 scala> Array("spark","hive","hadoop").map(_*2) res6: Array[String] = Array(sparkspark, hivehive, hadoophadoop)

    List類型:

    scala> val list=List("Spark"->1,"hive"->2,"hadoop"->2) list: List[(String, Int)] = List((Spark,1), (hive,2), (hadoop,2))//寫法1 scala> list.map(x=>x._1) res20: List[String] = List(Spark, hive, hadoop) //寫法2 scala> list.map(_._1) res21: List[String] = List(Spark, hive, hadoop)scala> list.map(_._2) res22: List[Int] = List(1, 2, 2)

    Map類型:

    //寫法1 scala> Map("spark"->1,"hive"->2,"hadoop"->3).map(_._1) res23: scala.collection.immutable.Iterable[String] = List(spark, hive, hadoop)scala> Map("spark"->1,"hive"->2,"hadoop"->3).map(_._2) res24: scala.collection.immutable.Iterable[Int] = List(1, 2, 3)//寫法2 scala> Map("spark"->1,"hive"->2,"hadoop"->3).map(x=>x._2) res25: scala.collection.immutable.Iterable[Int] = List(1, 2, 3)scala> Map("spark"->1,"hive"->2,"hadoop"->3).map(x=>x._1) res26: scala.collection.immutable.Iterable[String] = List(spark, hive, hadoop)

    2 flatMap函數

    //寫法1 scala> List(List(1,2,3),List(2,3,4)).flatMap(x=>x) res40: List[Int] = List(1, 2, 3, 2, 3, 4)//寫法2 scala> List(List(1,2,3),List(2,3,4)).flatMap(x=>x.map(y=>y)) res41: List[Int] = List(1, 2, 3, 2, 3, 4)

    3 filter函數

    scala> Array(1,2,4,3,5).filter(_>3) res48: Array[Int] = Array(4, 5)scala> List("List","Set","Array").filter(_.length>3) res49: List[String] = List(List, Array)scala> Map("List"->3,"Set"->5,"Array"->7).filter(_._2>3) res50: scala.collection.immutable.Map[String,Int] = Map(Set -> 5, Array -> 7)

    4 reduce函數

    //寫法1 scala> Array(1,2,4,3,5).reduce(_+_) res51: Int = 15scala> List("Spark","Hive","Hadoop").reduce(_+_) res52: String = SparkHiveHadoop//寫法2 scala> Array(1,2,4,3,5).reduce((x:Int,y:Int)=>{println(x,y);x+y}) (1,2) (3,4) (7,3) (10,5) res60: Int = 15scala> Array(1,2,4,3,5).reduceLeft((x:Int,y:Int)=>{println(x,y);x+y}) (1,2) (3,4) (7,3) (10,5) res61: Int = 15scala> Array(1,2,4,3,5).reduceRight((x:Int,y:Int)=>{println(x,y);x+y}) (3,5) (4,8) (2,12) (1,14) res62: Int = 15

    5 fold函數

    scala> Array(1,2,4,3,5).foldLeft(0)((x:Int,y:Int)=>{println(x,y);x+y}) (0,1) (1,2) (3,4) (7,3) (10,5) res66: Int = 15scala> Array(1,2,4,3,5).foldRight(0)((x:Int,y:Int)=>{println(x,y);x+y}) (5,0) (3,5) (4,8) (2,12) (1,14) res67: Int = 15scala> Array(1,2,4,3,5).foldLeft(0)(_+_) res68: Int = 15scala> Array(1,2,4,3,5).foldRight(10)(_+_) res69: Int = 25// /:相當于foldLeft scala> (0 /: Array(1,2,4,3,5)) (_+_) res70: Int = 15scala> (0 /: Array(1,2,4,3,5)) ((x:Int,y:Int)=>{println(x,y);x+y}) (0,1) (1,2) (3,4) (7,3) (10,5) res72: Int = 15

    6 scan函數

    //從左掃描,每步的結果都保存起來,執行完成后生成數組 scala> Array(1,2,4,3,5).scanLeft(0)((x:Int,y:Int)=>{println(x,y);x+y}) (0,1) (1,2) (3,4) (7,3) (10,5) res73: Array[Int] = Array(0, 1, 3, 7, 10, 15)//從右掃描,每步的結果都保存起來,執行完成后生成數組 scala> Array(1,2,4,3,5).scanRight(0)((x:Int,y:Int)=>{println(x,y);x+y}) (5,0) (3,5) (4,8) (2,12) (1,14) res74: Array[Int] = Array(15, 14, 12, 8, 5, 0)

    3. SAM轉換

    在Java的GUI編程中,在設置某個按鈕的監聽器的時候,我們常常會使用下面的代碼(利用scala進行代碼開發):

    var counter=0; val button=new JButton("click") button.addActionListener(new ActionListener{override def actionPerformed(event:ActionEvent){counter+=1} })

    上面代碼在addActionListener方法中定義了一個實現了ActionListener接口的匿名內部類,代碼中

    new ActionListener{override def actionPerformed(event:ActionEvent){}

    這部分稱為樣板代碼,即在任何實現該接口的類中都需要這樣用,重復性較高,由于ActionListener接口只有一個actionPerformed方法,它被稱為simple abstract method(SAM)。SAM轉換是指只給addActionListener方法傳遞一個參數

    button.addActionListener((event:ActionEvent)=>counter+=1)//并提供一個隱式轉換,我們后面會具體講隱式轉換 implict def makeAction(action:(event:ActionEvent)=>Unit){new ActionListener{override def actionPerformed(event:ActionEvent){action(event)} }

    這樣的話,在進行GUI編程的時候,可以省略非常多的樣板代碼,使代碼更簡潔。

    4. 函數柯里化

    在函數與閉包那一節中,我們定義了下面這樣的一個函數

    //mutiplyBy這個函數的返回值是一個函數 //該函數的輸入是Doulbe,返回值也是Double scala> def multiplyBy(factor:Double)=(x:Double)=>factor*x multiplyBy: (factor: Double)Double => Double//返回的函數作為值函數賦值給變量x scala> val x=multiplyBy(10) x: Double => Double = <function1>//變量x現在可以直接當函數使用 scala> x(50) res33: Double = 500.0

    上述代碼可以像這樣使用:

    scala> def multiplyBy(factor:Double)=(x:Double)=>factor*x multiplyBy: (factor: Double)Double => Double//這是高階函數調用的另外一種形式 scala> multiplyBy(10)(50) res77: Double = 500.0

    那函數柯里化(curry)是怎么樣的呢?其實就是將multiplyBy函數定義成如下形式

    scala> def multiplyBy(factor:Double)(x:Double)=x*factor multiplyBy: (factor: Double)(x: Double)Double
    • 1

    即通過(factor:Double)(x:Double)定義函數參數,該函數的調用方式如下:

    //柯里化的函數調用方式 scala> multiplyBy(10)(50) res81: Double = 500.0//但此時它不能像def multiplyBy(factor:Double)=(x:Double)=>factor*x函數一樣,可以輸入單個參數進行調用 scala> multiplyBy(10)<console>:10: error: missing arguments for method multiplyBy; follow this method with `_' if you want to treat it as a partially applied funct ionmultiplyBy(10)^

    錯誤提示函數multiplyBy缺少參數,如果要這么做的話,需要將其定義為偏函數

    scala> multiplyBy(10)_ res79: Double => Double = <function1>

    那現在我們接著對偏函數進行介紹

    5. 部分應用函數

    在數組那一節中,我們講到,Scala中的數組可以通過foreach方法將其內容打印出來,代碼如下:

    scala>Array("Hadoop","Hive","Spark")foreach(x=>println(x)) Hadoop Hive Spark //上面的代碼等價于下面的代碼 scala> def print(x:String)=println(x) print: (x: String)Unitscala> Array("Hadoop","Hive","Spark")foreach(print) Hadoop Hive Spark
    • 1

    那什么是部分應用函數呢,所謂部分應用函數就是指,當函數有多個參數,而在我們使用該函數時我們不想提供所有參數(假設函數有3個函數),只提供0~2個參數,此時得到的函數便是部分應用函數,定義上述print函數的部分應用函數代碼如下:

    //定義print的部分應用函數 scala> val p=print _ p: String => Unit = <function1>scala> Array("Hadoop","Hive","Spark")foreach(p) Hadoop Hive Sparkscala> Array("Hadoop","Hive","Spark")foreach(print _) Hadoop Hive Spark

    在上面的簡化輸出代碼中,下劃線_并不是占位符的作用,而是作為部分應用函數的定義符。前面我演示了一個參數的函數部分應用函數的定義方式,現在我們定義一個多個輸入參數的函數,代碼如下:

    //定義一個求和函數 scala> def sum(x:Int,y:Int,z:Int)=x+y+z sum: (x: Int, y: Int, z: Int)Int//不指定任何參數的部分應用函數 scala> val s1=sum _ s1: (Int, Int, Int) => Int = <function3>scala> s1(1,2,3) res91: Int = 6//指定兩個參數的部分應用函數 scala> val s2=sum(1,_:Int,3) s2: Int => Int = <function1>scala> s2(2) res92: Int = 6//指定一個參數的部分應用函數 scala> val s3=sum(1,_:Int,_:Int) s3: (Int, Int) => Int = <function2>scala> s3(2,3) res93: Int = 6

    在函數柯里化那部分,我們提到柯里化的multiplyBy函數輸入單個參數,它并不會像沒有柯里化的函數那樣返回一個函數,而是會報錯,如果需要其返回函數的話,需要定義其部分應用函數,代碼如下:

    //定義multiplyBy函數的部分應用函數,它返回的是一個函數 scala> val m=multiplyBy(10)_ m: Double => Double = <function1>scala> m(50) res94: Double = 500.0

    總結

    以上是生活随笔為你收集整理的Scala入门到精通——第十三节 高阶函数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。