Scala語言學(xué)習(xí)三 (函數(shù)式編程)

函數(shù)式編程

我們將來使用Spark/Flink的大量業(yè)務(wù)代碼都會使用到函數(shù)式編程擎场。下面的這些操作是學(xué)習(xí)的重點(diǎn)。

  • 遍歷( foreach )

  • 映射( map )

  • 映射扁平化( flatmap )

  • 過濾( filter )

  • 是否存在( exists )

  • 排序( sorted 、 sortBy 、 sortWith )

  • 分組( groupBy )

  • 聚合計(jì)算( reduce )

  • 折疊( fold )

遍歷 | foreach

之前捻激,學(xué)習(xí)過了使用for表達(dá)式來遍歷集合钧排。我們接下來將學(xué)習(xí)scala的函數(shù)式編程敦腔,使

用 foreach 方法來進(jìn)行遍歷、迭代恨溜。它可以讓代碼更加簡潔符衔。

語法

foreach(f: (A) ? Unit): Unit

解析

foreach API 說明
參數(shù) f: (A) ? Unit 接收一個(gè)函數(shù)對象,函數(shù)對象的輸入?yún)?shù)為集合的元素糟袁,返回值為空
返回值 Unit

foreach執(zhí)行過程

Snipaste_2020-08-14_18-23-09

書寫參數(shù)類型的遍歷

示例

有一個(gè)列表判族,包含以下元素1,2,3,4,請使用foreach方法遍歷打印每個(gè)元素

// 定義一個(gè)列表 
scala> val a = List(1,2,3,4) 
a: List[Int] = List(1, 2, 3, 4) 

// 迭代打印 
scala> a.foreach((x:Int)=>println(x))

使用類型推斷簡化函數(shù)定義

上述案例函數(shù)定義有點(diǎn)啰嗦项戴,我們有更簡潔的寫法形帮。因?yàn)槭褂胒oreach去迭代列表,而列表中的每

個(gè)元素類型是確定的

  • scala可以自動來推斷出來集合中每個(gè)元素參數(shù)的類型

  • 創(chuàng)建函數(shù)時(shí),可以省略其參數(shù)列表的類型

示例:

  1. 有一個(gè)列表辩撑,包含以下元素1,2,3,4界斜,請使用foreach方法遍歷打印每個(gè)元素

  2. 使用類型推斷簡化函數(shù)定義

scala> val a = List(1,2,3,4) 
a: List[Int] = List(1, 2, 3, 4) 

// 省略參數(shù)類型 
scala> a.foreach(x=>println(x))

使用下劃線來簡化函數(shù)定義

當(dāng)函數(shù)參數(shù),只在函數(shù)體中出現(xiàn)一次合冀,而且函數(shù)體沒有嵌套調(diào)用時(shí)各薇,可以使用下劃線來簡化函數(shù)定

示例:

  1. 有一個(gè)列表,包含以下元素1,2,3,4君躺,請使用foreach方法遍歷打印每個(gè)元素

  2. 使用下劃線簡化函數(shù)定義

scala> val a = List(1,2,3,4) 
a: List[Int] = List(1, 2, 3, 4) 

a.foreach(println(_))
  • 如果方法參數(shù)是函數(shù)峭判,如果出現(xiàn)了下劃線,scala編譯器會自動將代碼封裝到一個(gè)函數(shù)中

  • 參數(shù)列表也是由scala編譯器自動處理

映射 | map

集合的映射操作是將來在編寫Spark/Flink用得最多的操作棕叫,是我們必須要掌握林螃。

語法

def map[B](f: (A) ? B): TraversableOnce[B]

解析

map方法 API 說明
泛型 [B] 指定map方法最終返回的集合泛型
參數(shù) f: (A) ? B 傳入一個(gè)函數(shù)對象,該函數(shù)接收一個(gè)類型A(要轉(zhuǎn)換的列表元素)俺泣,返回值為類型B
返回值 TraversableOnce[B] B類型集合

示例:

  1. 創(chuàng)建一個(gè)列表疗认,包含元素1,2,3,4

  2. 對List中的每一個(gè)元素加1

scala> a.map(x=>x+1) 
res4: List[Int] = List(2, 3, 4, 5)

示例:

  1. 創(chuàng)建一個(gè)列表,包含元素1,2,3,4

  2. 使用下劃線來定義函數(shù)砌滞,對List中的每一個(gè)元素加1

scala> val a = List(1,2,3,4) 
a: List[Int] = List(1, 2, 3, 4) 

scala> a.map(_ + 1)

扁平化映射 | flatmap

映射扁平化也是將來用得非常多的操作侮邀,也是必須要掌握的。

Snipaste_2020-08-14_20-45-34
  • map是將列表中的元素轉(zhuǎn)換為一個(gè)List
  • flatten再將整個(gè)列表進(jìn)行扁平化

語法

def flatMap[B](f: (A) ? GenTraversableOnce[B]): TraversableOnce[B]

方法解析

flatmap方法 API 說明
泛型 [B] 最終要轉(zhuǎn)換的集合元素類型
參數(shù) f: (A) ? GenTraversableOnce[B] 傳入一個(gè)函數(shù)對象贝润,函數(shù)的參數(shù)是集合的元素绊茧,函數(shù)的返回值是一個(gè)集合
返回值 TraversableOnce[B] B類型的集合

示例

  1. 有一個(gè)包含了若干個(gè)文本行的列表:"hadoop hive spark flink flume", "kudu hbase sqoop

storm"

  1. 獲取到文本行中的每一個(gè)單詞,并將每一個(gè)單詞都放到列表中

步驟

  1. 使用map將文本行拆分成數(shù)組

  2. 再對數(shù)組進(jìn)行扁平化

Snipaste_2020-08-14_20-59-43

如果不使用flatmap來處理代碼

// 定義文本行列表 
scala> val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm") 
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm) 

// 使用map將文本行轉(zhuǎn)換為單詞數(shù)組 
scala> a.map(x=>x.split(" ")) 
res5: List[Array[String]] = List(Array(hadoop, hive, spark, flink, flume), Array(kudu, hbase, sqoop, storm)) 

// 扁平化打掘,將數(shù)組中的元素扁平
scala> a.map(x=>x.split(" ")).flatten 
res6: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)

使用flatmap簡化操作

scala> val a = List("hadoop hive spark flink flume", "kudu hbase sqoop storm") 
a: List[String] = List(hadoop hive spark flink flume, kudu hbase sqoop storm) 

scala> a.flatMap(_.split(" ")) 
res7: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)

過濾 | fliter

過濾符合一定條件的元素

Snipaste_2020-08-14_21-10-23

語法

def filter(p: (A) ? Boolean): TraversableOnce[A]

方法解析

fliter方法 API 說明
參數(shù) p: (A) ? Boolean 傳入一個(gè)函數(shù)對象华畏,接收一個(gè)集合類型的參數(shù) ,返回布爾類型尊蚁,滿足條件返回true, 不滿足返回false
返回值 TraversableOnce[A] 列表

示例

  1. 有一個(gè)數(shù)字列表亡笑,元素為:1,2,3,4,5,6,7,8,9

  2. 請過濾出所有的偶數(shù)

scala> List(1,2,3,4,5,6,7,8,9).filter(_ % 2 == 0) 
res8: List[Int] = List(2, 4, 6, 8)

默認(rèn)排序 | sorted

示例

  1. 定義一個(gè)列表,包含以下元素: 3, 1, 2, 9, 7

  2. 對列表進(jìn)行升序排序

scala> List(3,1,2,9,7).sorted 
res16: List[Int] = List(1, 2, 3, 7, 9)

指定字段排序 | sortBy

根據(jù)傳入的函數(shù)轉(zhuǎn)換后横朋,再進(jìn)行排序

示例

  1. 有一個(gè)列表仑乌,分別包含幾下文本行:"01 hadoop", "02 flume", "03 hive", "04 spark"

  2. 請按照單詞字母進(jìn)行排序

scala> val a = List("01 hadoop", "02 flume", "03 hive", "04 spark") 
a: List[String] = List(01 hadoop, 02 flume, 03 hive, 04 spark) 

// 獲取單詞字段 
scala> a.sortBy(_.split(" ")(1)) 
res8: List[String] = List(02 flume, 01 hadoop, 03 hive, 04 spark)

自定義排序 | sortWith

示例

  1. 有一個(gè)列表,包含以下元素:2,3,1,6,4,5

  2. 使用sortBy對列表進(jìn)行降序排序

如果不使用sortwith步驟

scala> val a = List(2,3,1,6,4,5) 
a: List[Int] = List(2, 3, 1, 6, 4, 5) 

scala> a.sortWith((x,y) => if(x<y)true else false) 
res15: List[Int] = List(1, 2, 3, 4, 5, 6) 

scala> res15.reverse 
res18: List[Int] = List(6, 5, 4, 3, 2, 1)

使用sortwith

scala> val a = List(2,3,1,6,4,5) 
a: List[Int] = List(2, 3, 1, 6, 4, 5) 

// 函數(shù)參數(shù)只在函數(shù)中出現(xiàn)一次琴锭,可以使用下劃線代替 
scala> a.sortWith(_ < _).reverse 
res19: List[Int] = List(6, 5, 4, 3, 2, 1)

分組 | groupBy

我們?nèi)绻獙?shù)據(jù)按照分組來進(jìn)行統(tǒng)計(jì)分析晰甚,就需要使用到分組方法

語法

def groupBy[K](f: (A) ? K): Map[K, List[A]]
Snipaste_2020-08-15_09-12-39

示例

  1. 有一個(gè)列表,包含了學(xué)生的姓名和性別:

"張三", "男"

"李四", "女"

"王五", "男"

  1. 請按照性別進(jìn)行分組决帖,統(tǒng)計(jì)不同性別的學(xué)生人數(shù)

步驟

  1. 定義一個(gè)元組列表來保存學(xué)生姓名和性別

  2. 按照性別進(jìn)行分組

  3. 將分組后的Map轉(zhuǎn)換為列表:List(("男" -> 2), ("女" -> 1))

scala> val a = List("張三"->"男", "李四"->"女", "王五"->"男") 
a: List[(String, String)] = List((張三,男), (李四,女), (王五,男)) 

// 按照性別分組 
scala> a.groupBy(_._2) 
res0: scala.collection.immutable.Map[String,List[(String, String)]] = Map(男 -> List(( 張三,男), (王五,男)), 女 -> List((李四,女)))

// 將分組后的映射轉(zhuǎn)換為性別/人數(shù)元組列表 
scala> res0.map(x => x._1 -> x._2.size) 
res3: scala.collection.immutable.Map[String,Int] = Map(男 -> 2, 女 -> 1)

聚合 | reduce

reduce表示將列表厕九,傳入一個(gè)函數(shù)進(jìn)行聚合計(jì)算

語法:

def reduce[A1 >: A](op: (A1, A1) ? A1): A1
Snipaste_2020-08-15_09-34-28

示例

  1. 定義一個(gè)列表,包含以下元素:1,2,3,4,5,6,7,8,9,10

  2. 使用reduce計(jì)算所有元素的和

scala> val a = List(1,2,3,4,5,6,7,8,9,10) 
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 

scala> a.reduce((x,y) => x + y) 
res5: Int = 55 

// 第一個(gè)下劃線表示第一個(gè)參數(shù)地回,就是歷史的聚合數(shù)據(jù)結(jié)果 
// 第二個(gè)下劃線表示第二個(gè)參數(shù)扁远,就是當(dāng)前要聚合的數(shù)據(jù)元素 

scala> a.reduce(_ + _) 
res53: Int = 55

// 與reduce一樣俊鱼,從左往右計(jì)算 
scala> a.reduceLeft(_ + _) 
res0: Int = 55 

// 從右往左聚合計(jì)算 
scala> a.reduceRight(_ + _) 
res1: Int = 55

折疊 | fold

fold與reduce很像,但是多了一個(gè)指定初始值參數(shù)

語法

def fold[A1 >: A](z: A1)(op: (A1, A1) ? A1): A1

示例

  1. 定義一個(gè)列表畅买,包含以下元素:1,2,3,4,5,6,7,8,9,10

  2. 使用fold方法計(jì)算所有元素的和

scala> val a = List(1,2,3,4,5,6,7,8,9,10) 
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 

scala> a.fold(0)(_ + _) 
res4: Int = 155
  • fold和foldLet效果一致并闲,表示從左往右計(jì)算

  • foldRight表示從右往左計(jì)算

  • z的值為初始值,比如寫10皮获,就是從10開始累加焙蚓,如果是上述的0,則從0開始累加

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洒宝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子萌京,更是在濱河造成了極大的恐慌雁歌,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件知残,死亡現(xiàn)場離奇詭異靠瞎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)求妹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門乏盐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人制恍,你說我怎么就攤上這事父能。” “怎么了净神?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵何吝,是天一觀的道長。 經(jīng)常有香客問我鹃唯,道長爱榕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任坡慌,我火速辦了婚禮黔酥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洪橘。我一直安慰自己跪者,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布梨树。 她就那樣靜靜地躺著坑夯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抡四。 梳的紋絲不亂的頭發(fā)上柜蜈,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天仗谆,我揣著相機(jī)與錄音,去河邊找鬼淑履。 笑死隶垮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秘噪。 我是一名探鬼主播狸吞,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼指煎!你這毒婦竟也來了蹋偏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤至壤,失蹤者是張志新(化名)和其女友劉穎威始,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體像街,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黎棠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镰绎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脓斩。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖畴栖,靈堂內(nèi)的尸體忽然破棺而出随静,到底是詐尸還是另有隱情,我是刑警寧澤驶臊,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布挪挤,位于F島的核電站,受9級特大地震影響关翎,放射性物質(zhì)發(fā)生泄漏扛门。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一纵寝、第九天 我趴在偏房一處隱蔽的房頂上張望论寨。 院中可真熱鬧,春花似錦爽茴、人聲如沸葬凳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽火焰。三九已至,卻和暖如春胧沫,著一層夾襖步出監(jiān)牢的瞬間昌简,已是汗流浹背占业。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纯赎,地道東北人谦疾。 一個(gè)月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像犬金,于是被迫代替她去往敵國和親念恍。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344