當前位置:網站首頁>scala編程(初級)
scala編程(初級)
2022-07-23 21:07:41【大寧哥】
Scala
scala安裝
#編譯運行scala程序,需要:
JDK(jvm)
Scala編譯器(scala SDK)
安裝JDK (java解釋器)
#安裝JDK 1.8 64比特, 並配置環境變量.
安裝Scala SDK (scala解釋器)
#安裝Scala SDK
windows : scala-2.12.1.msi
Linux : scala-2.11.12.tar.gz
安裝完畢之後,測試是否安裝成功: scala -version
安裝IDEA插件
#先下載idealU
#然後再下載Idealu支持Scala的插件
具體步驟占時略
概念
scala簡介
//scala 運行在Jvm上這點和Java一樣。 Scala是多範式編程語言。
//scala支持面向對象和函數式編程。
//scala剛剛問世的時候是個不起眼的小語種。但是隨著Spark,Kafka等基於Scala的大數據框架的興起,Scala就火了呀。
//scala的優勢是它的錶達性。
為什麼使用Scala?
//開發大數據應用(Spark, Flink)
//錶達能力强,一行抵得上java多行
//兼容java,可以訪問龐大的Java類庫。例如Mysql, redies, freemrker activemq 等
Scala和Java對比
//java代碼比較繁瑣, Scala代碼比較簡潔. (三行Scala抵得上三十四行Java. 誇張的說!)
//批量操作,scala一行map就差不多够了,可是Java需要便利循環處理
Scala編譯執行過程
java程序是如何編譯.執行的?
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kG0zE3s7-1658546372321)(scala.assets/image-20211027213633410.png)]
scala程序是如何編譯,執行的?
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IHPPUNlx-1658546372323)(scala.assets/image-20211027213836372.png)]
// java編譯器和scala編譯器不通用哦.
// scala也有自己的類庫, scala也可以使用java類庫哦.
// scala
基礎
交互式,文件式例子
交互式
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-grLBWoIS-1658546372323)(scala.assets/image-20210830133231577.png)]
文件式
//HelloWorld.scala 代碼如下:
object HelloWorld {
/* 這是我的第一個 Scala 程序 * 以下程序將輸出'Hello World!' */
def main(args: Array[String]) {
println("Hello, world!") // 輸出 Hello World
}
}
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2dgHhZh3-1658546372324)(scala.assets/image-20210830133434401.png)]
語法需要注意
#1. 區分大小寫 - Scala是大小寫敏感的,這意味著標識Hello 和 hello在Scala中會有不同的含義。
#2. 類名 - 對於所有的類名的第一個字母要大寫。如果需要使用幾個單詞來構成一個類的名稱,每個單詞的第一個字母要大寫。
示例:class MyFirstScalaClass
#3. 方法名稱 - 所有的方法名稱的第一個字母用小寫。如果若幹單詞被用於構成方法的名稱,則每個單詞的第一個字母應大寫。
示例:def myMethodName()
#4. 程序文件名 - 程序文件的名稱應該與對象名稱完全匹配(新版本不需要了,但建議保留這種習慣)。保存文件時,應該保存它使用的對象名稱(記住Scala是區分大小寫),並追加".scala"為文件擴展名。 (如果文件名和對象名稱不匹配,程序將無法編譯)。
示例: 假設"HelloWorld"是對象的名稱。那麼該文件應保存為'HelloWorld.scala"
#5. def main(args: Array[String]) - Scala程序從main()方法開始處理,這是每一個Scala程序的强制程序入口部分。
Scala 變量
// 1.scala中var聲明變量,val聲明常量
val定義的變量不可以重新賦值,但是var定義的可以.
// 2.Scala 可以使用類型推斷。
val name = "占山"
惰性賦值
//當一些變量保存的數據較大時候,但是不需要馬上加載到JVM內存中,可以使用惰性賦值來提高效率
當用到這個變量的時候,才會加載到JVM中
//語法:
lazy val/var 變量名 = 錶達式
例如有個複雜的Sql語言,我們希望只有用到SQL語句的時候才加載他.。 如果不使用lazy,就直接加載到內存了。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EEWagGoH-1658546372324)(scala.assets/image-20211028100331149.png)]
數據類型
//scala中有著與java相同的數據類型。 如下說說與之不同的地方:
scala中所有的類型都使用大寫字母開頭。
整形使用Int,而不是Integer
scala 申請變量的時候可以不寫類型,讓scala編譯器自己推斷去吧。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tpEVg3jR-1658546372325)(scala.assets/image-20210830135413572.png)]
Scala類型層次結構
//Scala的數據類型也是“單根繼承”體系, 都是繼承Any這個類型
//AnyVal 是所有“值類型”的父類。
//AnyRef 是所有“引用類型”的父類
//Unit 錶示“空類型”
他只有一個實例() 。它類似於java中的void, 但是scala比java更加的面向對象。
//Null 所有“引用類型”的子類。
也就是Nul類型可以賦值給所有“引用類型”
//Nothing 所有類型的子類。
Nothing 錶示方法拋出异常的時候,返回的子類。。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qauj3vwv-1658546372325)(scala.assets/image-20211028104338861.png)]
Null 類型是不可以賦值給 AnyVal 下面的類型的, 只可以賦值給AnyRef下的類型。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tJBvySMO-1658546372326)(scala.assets/image-20211028110559816.png)]
運算符
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aCzNU0pw-1658546372326)(scala.assets/image-20211028103114605.png)]
條件錶達式(if)
//if 的使用,語法和java一樣。在此不多bb。 下面主要說和java不一樣的地方:
Scala中if是有返回值的。
Scala中沒有三元錶達式,可以使用if錶達式代替 三元錶達式
有返回值的if
例:當sex 是 “male”就返回1 , 否則就返回0
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2gq23e7w-1658546372327)(scala.assets/image-20211028113904773.png)]
塊錶達式
//scala中使用{} 錶示塊錶達式
和if錶示式一樣,塊錶達式也是有值的。值就是最後一個錶達式的值。
// 塊錶達式是很牛逼的一個東西。這玩意用的好,代碼就精巧。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-O0yxjpK9-1658546372327)(scala.assets/image-20211028115157383.png)]
循環
for
遍曆循環1到9
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-PStir5sz-1658546372328)(scala.assets/image-20211028150220215.png)]
在scala中,數字也是一個對象,也可以調用 .to方法。
//scala中 x.to(y) 相當於 python 中 range(x, y+1)
// 1.to(10) 也可以寫成 1 to 10
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3CUMIEne-1658546372328)(scala.assets/image-20211028150629317.png)]
for嵌套循環
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8AR7aK0Q-1658546372329)(scala.assets/image-20211028152304039.png)]
for的守衛
for錶達式中,可以添加if判斷語句,這個if判斷就稱之為守衛。我們可以使用守衛讓for錶達式更簡潔。
語法:
for(i <- 錶達式/數組/集合 if 錶達式) {
// 錶達式
}
//錶示,當if後面這個錶達式式True的時候,才能進入下面的操作。
例:用for錶達式打印1-10之間內 能整除3的數字
for(i <- 1.to(10) if(i%3==0)){
println(i)
}
等價於:
for(i <- 1.to(10)){
if(i%3==0){
println(i)
}
}
for 的推導式
// 可以使用for推導式 生成一個心的集合(一組數據)
// 我們把 使用yield的for錶達式稱之為“推導式”
例:生成10, 20, 30, … 100
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YDlFwySD-1658546372329)(scala.assets/image-20211028154508520.png)]
跟python的 v = [ i*10 for i in range(11)] 有點像哦。
while
略。
do … while
略。
break
* 在scala中,類似Java和C++的break/continue關鍵字被移除了
* 如果一定要使用break/continue,就需要使用scala.util.control包的Break類的breable和break方法。
* 導入Breaks包 import scala.util.control.Breaks._
* 使用breakable將for錶達式包起來
* for錶達式中需要退出循環的地方,添加`break()`方法調用
例:
// 導入scala.util.control包下的Break
import scala.util.control.Breaks._
breakable{
for(i <- 1 to 100) {
if(i >= 50) break()
else println(i)
}
}
continue
//continue的實現與break類似,但有一點不同:
實現break是用breakable{
}將整個for錶達式包起來,
而實現continue是用breakable{
}將for錶達式的循環體包含起來就可以了
例:打印1-100的數字,使用for錶達式來遍曆,如果數字能整除10,不打印
// 導入scala.util.control包下的Break
import scala.util.control.Breaks._
for(i <- 1 to 100 ) {
breakable{
if(i % 10 == 0) break()
else println(i)
}
}
方法,函數
Scala 有方法與函數,二者在語義上的區別很小。Scala 方法是類的一部分,而函數是一個對象可以賦值給一個變量。換句話來說在類中定義的函數即是方法。
Scala 中的方法跟 Java 的類似,語法不一樣,方法是組成類的一部分.
Scala 中的函數則是一個完整的對象,Scala 中的函數其實就是繼承了 Trait 的類的對象。
Scala 中使用 val 語句可以定義函數,def 語句定義方法。
注意:有些翻譯上函數(function)與方法(method)是沒有區別的。
方法
語法
def methodName (參數名:參數類型, 參數名:參數類型) : [return type] = {
// 方法體:一系列的代碼
}
/* * 參數列錶的參數類型不能省略 * 返回值類型可以省略,由scala編譯器自動推斷 * 返回值可以不寫return,默認就是{}塊錶達式的值 */
例:定義一個方法,實現兩個整形數值相加,返回相加後的結果
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6MqCqlpd-1658546399390)(scala.assets/image-20211028161335519.png)]
標准寫法:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-bB9fBOOr-1658546399391)(scala.assets/image-20211028162119791.png)]
返回值推斷
//scala定義方法可以省略返回值,由scala自動推斷返回值類型。這樣方法定義後更加簡潔。
//定義遞歸方法,不能省略返回值類型
//return 什麼時候都可以不寫,看你心情。
例:定義遞歸方法(求階乘)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-R2mn2JxF-1658546399392)(scala.assets/image-20211028162618915.png)]
方法的參數
scala中的方法參數,使用比較靈活。它支持以下幾種類型的參數:
- 默認參數 (和py一樣)
- 帶名參數 (和py一樣)
- 變長參數 ( * )
1.默認參數:在定義方法時可以給參數定義一個默認值。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AXUIZ0qW-1658546399392)(scala.assets/image-20211028163213593.png)]
2.帶名參數:在調用方法時,可以指定參數的名稱來進行調用。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-CecpdFQc-1658546399393)(scala.assets/image-20211028163303876.png)]
3.邊長參數:如果方法的參數是不固定的,可以定義一個方法的參數是變長參數。
語法格式:
def 方法名(參數名:參數類型*):返回值類型 = {
方法體
}
//在參數類型後面加一個`*`號,錶示參數可以是0個或者多個
**例子:**定義一個計算若幹個值相加的方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5rmKjRe2-1658546399394)(scala.assets/image-20211028164018151.png)]
輸出:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-j12uuZkv-1658546399394)(scala.assets/image-20211028164038011.png)]
疑問:不定長參數的類型式什麼?猜想是數組。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2SNdvULt-1658546399395)(scala.assets/image-20211028164145483.png)]
輸出:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-YWdxewcX-1658546399395)(scala.assets/image-20211028164204031.png)]
答疑:是WrappendArray() ? 還是Seq[Int] ?
方法調用方式
//在scala中,有以下幾種方法調用方式,
後綴調用法
中綴調用法
花括號調用法
無括號調用法
//在後續編寫spark、flink程序時,我們會使用到這些方法調用方式。
1.後綴調用法
語法: 對象名.方法名(參數)
例:
Math.abs(-1)
1.to(10)
2.中綴調用法
語法: 對象名 方法名 參數 ; 如果有多個參數,使用括號括起來
例:
Math abs -1
1 to 10
3.花括號調用法
//方法只有一個參數,才能使用花括號調用法
Math.abs{
-10}
//{}錶示塊錶達式,快錶達式的返回值就是最後一個錶達式(之前說過,別忘了)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-x5lavozL-1658546399396)(scala.assets/image-20211029113909816.png)]
4.無符號調用法
//如果方法沒有參數,可以省略方法名後面的括號
def m3()=println("hello")
m3
5.操作符也是方法
在scala中:
所有的操作符都是方法
操作符是一個方法名字是符號的方法.
1 + 1 這個錶達式實際上也是一個方法調用哦。scala的特別之處,嘻嘻。
//下面不寫不知道,一寫麼的嚇一跳。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-70lgbz2i-1658546399396)(scala.assets/image-20211029113709782.png)]
函數
// scala支持函數是編程, 這個在編程Spark/flink程序中會大量使用,真特麼重要。
/* 函數是一個 對象(變量) 類似於方法,函數也有輸入參數和返回值 函數定義不需要使用def 定義 無需指定返回值類型 */
語法
val 函數變量名 = (參數名:參數類型, 參數名:參數類型....) => 函數體
猜想:
等價於python中 函數命=lambda 參數1,參數2 ... :函數體 (如:x = lambda x: x+1)
例:定義兩個數值相加的函數
scala> val add = (x:Int, y:Int) => x + y
add: (Int, Int) => Int = <function2>
scala> add(1,2)
res3: Int = 3
方法和函數的區別
/* 方法是隸屬於類或者對象的,在運行時,它是加載到JVM的方法區中 可以將函數對象賦值給一個變量,在運行時,它是加載到JVM的堆內存中 函數是一個對象,繼承自FunctionN,函數對象有apply,curried,toString,tupled這些方法。方法則沒有 */
**例:**方法無法賦值給變量,函數可以
既:
val 變量 = 函數名 ; 是正確的
此時 這個變量就是個函數。
val 變量 = 方法名 ; 是錯誤的
scala> val add1 = (x:Int, y:Int) => x+y
add1: (Int, Int) => Int = $$Lambda$1092/256869439@7b5833ee
scala> add1
res14: (Int, Int) => Int = $$Lambda$1092/256869439@7b5833ee
scala> add1(1,1)
res15: Int = 2
scala> val a1 = add1
a1: (Int, Int) => Int = $$Lambda$1092/256869439@7b5833ee
scala> a1(2,2)
res16: Int = 4
// --------------------------------------------------------------------
scala> def add2(x:Int, y:Int) = x+y
add2: (x: Int, y: Int)Int
scala> add2(1,1)
res18: Int = 2
scala> val a2 = add2
<console>:12: error: missing argument list for method add2
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `add2 _` or `add2(_,_)` instead of `add2`.
val a2 = add2
^
方法轉化為函數
// 有時候需要將方法轉換為函數,作為變量傳遞,就需要將方法轉換為函數
語法:
val 變量 = 方法名 _
**例:**將方法轉化為函數,賦值給變量
scala> def add(x:Int,y:Int)=x+y
add: (x: Int, y: Int)Int
scala> val a = add _
a: (Int, Int) => Int = <function2>
字符串(String)
//定義字符串方式
val S:String = "aaa" //使用雙引號
val S:String = """aaaa""" //使用三引號
val S:String = s"${
name}你好" //使用插值錶達式
//以s開頭; name是個變量或者錶達式
列出了 java.lang.String 常用方法
你可以在 Scala 中使用:
| 序號 | 方法及描述 |
|---|---|
| 1 | **char charAt(int index)**返回指定比特置的字符 |
| 2 | **int compareTo(Object o)**比較字符串與對象 |
| 3 | **int compareTo(String anotherString)**按字典順序比較兩個字符串 |
| 4 | **int compareToIgnoreCase(String str)**按字典順序比較兩個字符串,不考慮大小寫 |
| 5 | **String concat(String str)**將指定字符串連接到此字符串的結尾 |
| 6 | **boolean contentEquals(StringBuffer sb)**將此字符串與指定的 StringBuffer 比較。 |
| 7 | **static String copyValueOf(char[] data)**返回指定數組中錶示該字符序列的 String |
| 8 | **static String copyValueOf(char[] data, int offset, int count)**返回指定數組中錶示該字符序列的 String |
| 9 | **boolean endsWith(String suffix)**測試此字符串是否以指定的後綴結束 |
| 10 | **boolean equals(Object anObject)**將此字符串與指定的對象比較 |
| 11 | **boolean equalsIgnoreCase(String anotherString)**將此 String 與另一個 String 比較,不考慮大小寫 |
| 12 | **byte getBytes()**使用平臺的默認字符集將此 String 編碼為 byte 序列,並將結果存儲到一個新的 byte 數組中 |
| 13 | byte[] getBytes(String charsetName使用指定的字符集將此 String 編碼為 byte 序列,並將結果存儲到一個新的 byte 數組中 |
| 14 | **void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)**將字符從此字符串複制到目標字符數組 |
| 15 | **int hashCode()**返回此字符串的哈希碼 |
| 16 | **int indexOf(int ch)**返回指定字符在此字符串中第一次出現處的索引 |
| 17 | **int indexOf(int ch, int fromIndex)**返回在此字符串中第一次出現指定字符處的索引,從指定的索引開始搜索 |
| 18 | **int indexOf(String str)**返回指定子字符串在此字符串中第一次出現處的索引 |
| 19 | **int indexOf(String str, int fromIndex)**返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始 |
| 20 | **String intern()**返回字符串對象的規範化錶示形式 |
| 21 | **int lastIndexOf(int ch)**返回指定字符在此字符串中最後一次出現處的索引 |
| 22 | **int lastIndexOf(int ch, int fromIndex)**返回指定字符在此字符串中最後一次出現處的索引,從指定的索引處開始進行反向搜索 |
| 23 | **int lastIndexOf(String str)**返回指定子字符串在此字符串中最右邊出現處的索引 |
| 24 | **int lastIndexOf(String str, int fromIndex)**返回指定子字符串在此字符串中最後一次出現處的索引,從指定的索引開始反向搜索 |
| 25 | **int length()**返回此字符串的長度 |
| 26 | **boolean matches(String regex)**告知此字符串是否匹配給定的正則錶達式 |
| 27 | **boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)**測試兩個字符串區域是否相等 |
| 28 | **boolean regionMatches(int toffset, String other, int ooffset, int len)**測試兩個字符串區域是否相等 |
| 29 | **String replace(char oldChar, char newChar)**返回一個新的字符串,它是通過用 newChar 替換此字符串中出現的所有 oldChar 得到的 |
| 30 | String replaceAll(String regex, String replacement使用給定的 replacement 替換此字符串所有匹配給定的正則錶達式的子字符串 |
| 31 | **String replaceFirst(String regex, String replacement)**使用給定的 replacement 替換此字符串匹配給定的正則錶達式的第一個子字符串 |
| 32 | **String[] split(String regex)**根據給定正則錶達式的匹配拆分此字符串 |
| 33 | **String[] split(String regex, int limit)**根據匹配給定的正則錶達式來拆分此字符串 |
| 34 | **boolean startsWith(String prefix)**測試此字符串是否以指定的前綴開始 |
| 35 | **boolean startsWith(String prefix, int toffset)**測試此字符串從指定索引開始的子字符串是否以指定前綴開始。 |
| 36 | **CharSequence subSequence(int beginIndex, int endIndex)**返回一個新的字符序列,它是此序列的一個子序列 |
| 37 | **String substring(int beginIndex)**返回一個新的字符串,它是此字符串的一個子字符串 |
| 38 | **String substring(int beginIndex, int endIndex)**返回一個新字符串,它是此字符串的一個子字符串 |
| 39 | **char[] toCharArray()**將此字符串轉換為一個新的字符數組 |
| 40 | **String toLowerCase()**使用默認語言環境的規則將此 String 中的所有字符都轉換為小寫 |
| 41 | **String toLowerCase(Locale locale)**使用給定 Locale 的規則將此 String 中的所有字符都轉換為小寫 |
| 42 | **String toString()**返回此對象本身(它已經是一個字符串!) |
| 43 | **String toUpperCase()**使用默認語言環境的規則將此 String 中的所有字符都轉換為大寫 |
| 44 | **String toUpperCase(Locale locale)**使用給定 Locale 的規則將此 String 中的所有字符都轉換為大寫 |
| 45 | **String trim()**删除指定字符串的首尾空白符 |
| 46 | **static String valueOf(primitive data type x)**返回指定類型參數的字符串錶示形式 |
補充:
S.head
S.drop(n)
S.dropRight(n) 删除後面n個字符
字符串長度
str.length()
判斷是字符串子字串
//判斷str2在str1中的比特置
str1.indexOf(str2)
返回-1說明 不存在
字符串拼接
val str3 = str1.concat(str2)
或者
val str3 = str1 + str2
替換
str1.replaceAll("字符串1","字符串2") //將str1中 字符串1替換成字符串2
列錶(List)
//列錶是scala中最重要的、也是最常用的數據結構。List具備以下性質:
- 可以保存重複的值
- 有先後順序
//有兩種列錶,一種是不可變列錶、另一種是可變列錶
不可變列錶
//不可變列錶就是列錶的元素、長度都是不可變的。
//實際上元素,長度都是可以變的。 其實是可以改變的,例如:updated(), drop(),
准確的說“不可變列錶 只是長度不可以增加”
定義語法
//使用`List(元素1, 元素2, 元素3, ...)`來創建一個不可變列錶:
val/var 變量名 = List(元素1, 元素2, 元素3...)
//例如 : var L = List(2,4,9,5,3,6,1,7,8)
//使用`Nil`創建一個不可變的空列錶:
val/var 變量名 = Nil
//使用`::`方法創建一個不可變列錶
val/var 變量名 = 元素1 :: 元素2 :: Nil
//使用**::**拼接方式來創建列錶,必須在最後添加一個**Nil**
**例:**創建一個不可變列錶,存放以下幾個元素(1,2,3,4)
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
**例:**使用Nil創建一個不可變的空列錶
scala> val a = Nil
a: scala.collection.immutable.Nil.type = List()
**例:**使用::方法創建列錶,包含-2、-1兩個元素
scala> val a = -2 :: -1 :: Nil
a: List[Int] = List(-2, -1)
修改
將L(2) 替換成100
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iJSCMo2i-1658546399397)(scala.assets/image-20211027170608831.png)]
删除
删除前5個數據 L(5)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8yKEQt1C-1658546399398)(scala.assets/image-20211027170859736.png)]
foreach()
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ne3EDIS6-1658546399398)(scala.assets/image-20211027171140054.png)]
可變列錶
//可變列錶就是列錶的元素、長度都是可變的。
//要使用可變列錶,先要導入
import scala.collection.mutable.ListBuffer
//可變集合都在`mutable`包中
//不可變集合都在`immutable`包中(默認導入)
定義語法
//使用ListBuffer[元素類型]()創建空的可變列錶,語法結構:
val/var 變量名 = ListBuffer[Int]()
//使用ListBuffer(元素1, 元素2, 元素3...)創建可變列錶,語法結構:
val/var 變量名 = ListBuffer(元素1,元素2,元素3...)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8ScPkGe9-1658546399399)(scala.assets/image-20211029175647356.png)]
獲取元素(使用括號訪問(索引值))
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qVAMuAAp-1658546399399)(scala.assets/image-20211029175846690.png)]
添加元素(+=)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sUPqjn17-1658546399399)(scala.assets/image-20211029175938568.png)]
追加一個列錶(++=)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MXbURv9O-1658546399400)(scala.assets/image-20211029180022146.png)]
删除元素(-=)
從左邊起,删除第一個 特定元素
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IQVH3g5A-1658546399408)(scala.assets/image-20211029180057127.png)]
更改元素(使用括號獲取元素,然後進行賦值)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-V3pe10Oa-1658546399409)(scala.assets/image-20211029180143001.png)]
轉換為List(toList)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cCqK1zEY-1658546399409)(scala.assets/image-20211029180230402.png)]
轉換為Array(toArray)
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-S6Q1ophd-1658546399409)(scala.assets/image-20211029180257150.png)]
列錶常用操作
以下是列錶常用的操作:
- 判斷列錶是否為空(isEmpty)
- 拼接兩個列錶(++)
- 獲取列錶的首個元素(head)和剩餘部分(tail)
- 反轉列錶(reverse)
- 獲取前綴(take)、獲取後綴(drop)
- 扁平化(flaten)
- 拉鏈(zip)和拉開(unzip)
- 轉換字符串(toString)
- 生成字符串(mkString)
- 並集(union)去重(distinct)
- 交集(intersect)
- 差集(diff)
判斷列錶是否為空(isEmpty)
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> a.isEmpty
res51: Boolean = false
拼接兩個列錶(++)
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> val b = List(4,5,6)
b: List[Int] = List(4, 5, 6)
scala> a ++ b
res52: List[Int] = List(1, 2, 3, 4, 5, 6)
前面的類型為主
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SUHZpedu-1658546399410)(scala.assets/image-20211029182153619.png)]
獲取列錶的首個元素(head)和剩餘部分(tail)
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> a.head
res4: Int = 1
scala> a.tail
res5: List[Int] = List(2, 3)
反轉列錶(reverse)
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)
scala> a.reverse
res6: List[Int] = List(3, 2, 1)
獲取前綴(take)、獲取後綴(drop)
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)
scala> a.take(3)
res56: List[Int] = List(1, 2, 3)
scala> a.drop(3)
res60: List[Int] = List(4, 5)
扁平化(flaten)
scala> val a = List(List(1,2), List(3), List(4,5))
a: List[List[Int]] = List(List(1, 2), List(3), List(4, 5))
scala> a.flatten
res0: List[Int] = List(1, 2, 3, 4, 5)
拉鏈(zip)和拉開(unzip)
scala> val a = List("zhangsan", "lisi", "wangwu")
a: List[String] = List(zhangsan, lisi, wangwu)
scala> val b = List(19, 20, 21)
b: List[Int] = List(19, 20, 21)
scala> a.zip(b)
res1: List[(String, Int)] = List((zhangsan,19), (lisi,20), (wangwu,21))
scala> res1.unzip
res2: (List[String], List[Int]) = (List(zhangsan, lisi, wangwu),List(19, 20, 21))
轉換字符串(toString)
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> println(a.toString)
List(1, 2, 3, 4)
生成字符串(mkString)
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> a.mkString
res7: String = 1234
scala> a.mkString(":")
res8: String = 1:2:3:4
並集(union),去重(distinct)
scala> val a1 = List(1,2,3,4)
a1: List[Int] = List(1, 2, 3, 4)
scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)
// 並集操作
scala> a1.union(a2)
res17: List[Int] = List(1, 2, 3, 4, 3, 4, 5, 6)
// 可以調用distinct去重
scala> a1.union(a2).distinct
res18: List[Int] = List(1, 2, 3, 4, 5, 6)
交集(intersect)
scala> val a1 = List(1,2,3,4)
a1: List[Int] = List(1, 2, 3, 4)
scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)
scala> a1.intersect(a2)
res19: List[Int] = List(3, 4)
差集(diff)
scala> val a1 = List(1,2,3,4)
a1: List[Int] = List(1, 2, 3, 4)
scala> val a2 = List(3,4,5,6)
a2: List[Int] = List(3, 4, 5, 6)
scala> a1.diff(a2)
res24: List[Int] = List(1, 2)
找元素的index
list.indexOf(str) //找str在list中的索引,如果沒找到則返回-1
數組
定長數組(Array)
* 定長數組指的是數組的 長度 是 不允許改變 的
* 數組的 元素 是 可以改變 的
* 在scala中,數組的泛型使用`[]`來指定
* 使用`()`來獲取元素
定義Array
// 通過指定長度定義數組
val/var 變量名 = new Array[元素類型](數組長度)
如:val array = new Array[Int](3)
// 用元素直接初始化數組
val/var 變量名 = Array(元素1, 元素2, 元素3...)
如:val array = Array(4,12,6,3,8,9,5)
修改
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5dcFUOsb-1658546420774)(scala.assets/image-20211027172854141.png)]
Array排序
sortWith( )
//這種方法數組必須是:Int,Double, Float, Long
sortWith(_ < _) 從小到大
sortWith(_ > _) 從大到小
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lBwylalG-1658546420776)(scala.assets/image-20211027173107454.png)]
sortBy( )
/*按照某一列排序*/
// 默認從小到大排序
// .reverse錶示對列錶倒敘. sortBy和reverse配合實驗=>從大到小排序
按照第二列排序:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-BZz0upJa-1658546420776)(scala.assets/image-20211027173851618.png)]
變長數組(ArrayBuffer)
* 變長數組指的是數組的長度是可變的,可以往數組中添加、删除元素
* 創建變長數組,需要提前導入ArrayBuffer類
import scala.collection.mutable.ArrayBuffer
定義Buffer
//創建空的ArrayBuffer變長數組,語法結構:
val/var a = ArrayBuffer[元素類型]()
// 創建帶有初始元素的ArrayBuffer
val/var a = ArrayBuffer(元素1,元素2,元素3....)
删除
remove
//從data(i)起,連續删除 j個元素
data.remove(i, j)
例:從B(2)開始連續删除兩個數據。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Le5SlTrv-1658546420776)(scala.assets/image-20211027172342182.png)]
-=
//從左邊起,删除第一個x
data -= x
例:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-i9FoL03o-1658546420777)(scala.assets/image-20211029165402269.png)]
插入
insert
//在data.insert(i)比特置插入 x元素
data.insert(i, x)
**例:**把999插入到B(2)這個比特置
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fM953TdB-1658546420777)(scala.assets/image-20211027172442825.png)]
+=
//在data尾部添加 x (有點python的append的味道)
data += x
例:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6kKN5VLP-1658546420778)(scala.assets/image-20211029165639538.png)]
合並
++=
//data1 和 data2 可變數組合並
data1 ++= data2
例:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TZLzKkoZ-1658546420778)(scala.assets/image-20211029165921471.png)]
數組算法
求和 — sum
scala> val a = Array(1,2,3,4)
a: Array[Int] = Array(1, 2, 3, 4)
scala> a.sum
res49: Int = 10
最大值 — max
scala> val a = Array(4,1,2,4,10)
a: Array[Int] = Array(4, 1, 2, 4, 10)
scala> a.max
res50: Int = 10
最小值 — min
scala> val a = Array(4,1,2,4,10)
a: Array[Int] = Array(4, 1, 2, 4, 10)
scala> a.min
res51: Int = 1
昇排序 — sorted
數組反轉 — reverse
// 昇序排序
scala> a.sorted
res53: Array[Int] = Array(1, 2, 4, 4, 10)
// 降序
scala> a.sorted.reverse
res56: Array[Int] = Array(10, 4, 4, 2, 1)
元組
// 元組可以用來包含一組不同類型的值。例如:姓名,年齡,性別,出生年月。
// 元組的元素是不可變的。
語法
//使用括號來定義元組
val/var 元組 = (元素1, 元素2, 元素3....)
//使用箭頭來定義元組(元組只有兩個元素)
val/var 元組 = 元素1->元素2
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y871NuAp-1658546420779)(scala.assets/image-20211029172436615.png)]
訪問元組
// 使用_1、_2、_3....來訪問元組中的元素,_1錶示訪問第一個元素,依次類推
//注意,不可以用 t(i)來訪問哦
例:
scala> val a = "zhangsan" -> "male"
a: (String, String) = (zhangsan,male)
// 獲取第一個元素
scala> a._1
res41: String = zhangsan
// 獲取第二個元素
scala> a._2
res42: String = male
集合
Set(集)是代錶沒有重複元素的集合。Set具備以下性質:
1. 元素不重複
2. 不保證插入順序
scala 中的集也分為兩種,一種是不可變集,另一種是可變集。
不可變集
定義語法
//創建一個空的不可變集,語法格式:
val/var 變量名 = Set[類型]()
//給定元素來創建一個不可變集,語法格式:
val/var 變量名 = Set(元素1, 元素2, 元素3...)
例:
//定義一個空的不可變集
scala> val a = Set[Int]()
a: scala.collection.immutable.Set[Int] = Set()
//定義一個不可變集,保存以下元素:1,1,3,2,4,8
scala> val a = Set(1,1,3,2,4,8)
a: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 8, 4)
基本操作
- 獲取集的大小(size)
- 遍曆集(和遍曆數組一致)
- 添加一個元素,生成一個Set(`+`)
- 删除一個元素,生成一個Set(`-`)
- 拼接兩個集,生成一個Set(++)
- 拼接集和列錶,生成一個Set(++)
// 創建集,可以看出集合是的元素是單一,無序的。
scala> val a = Set(1,1,2,3,4,5)
a: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
獲取集的大小(size)
// 獲取集的大小
scala> a.size
res0: Int = 5
遍曆集(和遍曆數組一致)
// 遍曆集
scala> for(i <- a) println(i)
5
1
6
2
3
4
添加一個元素,生成一個Set(+)
//添加一個元素
scala> a + 100
res5: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4, 100)
删除一個元素,生成一個Set(-)
// 删除一個元素
scala> a - 1
res5: scala.collection.immutable.Set[Int] = Set(5, 2, 3, 4)
拼接兩個集,生成一個Set(++)
// 拼接兩個集
scala> a ++ Set(6,7,8)
res2: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 7, 3, 8, 4)
拼接集和列錶,生成一個Set(++)
// 拼接集和列錶
scala> a ++ List(6,7,8,9)
res6: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 9, 2, 7, 3, 8, 4)
可變集
定義方法
//可變集合不可變集的創建方式一致,只不過需要提前導入一個可變集類。
手動導入:
import scala.collection.mutable.Set
例:
import scala.collection.mutable.Set
scala> val a = Set(1,2,3,4)
a: scala.collection.mutable.Set[Int] = Set(1, 2, 3, 4)
操作方法
添加元素(+=)
scala> b
res28: scala.collection.mutable.Set[Int] = Set(1, 2, 3, 4)
scala> b += 111
res29: b.type = Set(1, 2, 3, 111, 4)
删除元素(-=)
scala> b
res31: scala.collection.mutable.Set[Int] = Set(1, 3, 111, 4)
scala> b -= 3
res32: b.type = Set(1, 111, 4)
映射(Map)— 字典
//Map可以稱之為映射。它是由鍵值對組成的集合。在scala中,Map也分為不可變Map和可變Map。
//Map 不就是他媽Python上的字典嗎。包括玩法都差不多
* 查 : map(舊鍵)
* 曾 : map(新鍵) = 值
* 改 : map(舊鍵) = 值
不可變Map
定義語法
val/var map = Map(鍵->值, 鍵->值, 鍵->值...) // 推薦,可讀性更好
val/var map = Map((鍵, 值), (鍵, 值), (鍵, 值), (鍵, 值)...)
**例:**定義一個映射,包含以下學生姓名和年齡數據。 獲取zhangsan的年齡
scala> val map = Map("zhangsan"->30, "lisi"->40)
map: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 40)
//或:
scala> val map = Map(("zhangsan", 30), ("lisi", 30))
map: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 30)
// 根據key獲取value
scala> map("zhangsan")
res10: Int = 30
可變Map
定義語法
// 定義語法與不可變Map一致。但定義可變Map需要手動導入
import scala.collection.mutable.Map
**例:**定義一個映射,包含以下學生姓名和年齡數據。 修改“zhangsan”的年齡為20
import scala.collection.mutable.Map
scala> val map = Map("zhangsan"->30, "lisi"->40)
map: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30)
// 修改value
scala> map("zhangsan") = 20
//添加一個值
scala> map("wangwu") = 36
scala> map
res44: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 66, wangwu -> 36)
Map基本操作
//Map操作 跟Python字典的玩法真的是一模一樣。
- 獲取值(`map(key)`)
- 獲取所有key(`map.keys`)
- 獲取所有value(`map.values`)
- 遍曆map集合
- getOrElse
- 增加key,value對
- 删除key
准備數據,不可變Map, 可變Map
scala> val map_NoChange = Map("zhangsan"->30, "lisi"->40)
map_NoChange: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 40)
scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map
scala> val map_Change = Map("zhangsan"->30, "lisi"->40)
map_Change: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30)
獲取值(map(key))
// 獲取zhagnsan的年齡
scala> map_NoChange("zhangsan")
res0: Int = 30
scala> map_Change("zhangsan")
res1: Int = 30
獲取所有key(map.keys)
// 獲取所有的學生姓名
scala> map_NoChange.keys
res2: Iterable[String] = Set(zhangsan, lisi)
scala> map_Change.keys
res3: Iterable[String] = Set(lisi, zhangsan)
獲取所有value(map.values)
// 獲取所有的學生年齡
scala> map_NoChange.values
res4: Iterable[Int] = MapLike.DefaultValuesIterable(30, 40)
scala> map_Change.values
res5: Iterable[Int] = HashMap(40, 30)
遍曆map集合
// 打印所有的學生姓名和年齡
scala> for((x,y) <- map_NoChange) println(s"$x $y")
zhangsan 30
lisi 40
scala> for((x,y) <- map_Change) println(s"$x $y")
lisi 40
zhangsan 30
查詢,若不存在返回x ( getOrElse(鍵, x) )
// 獲取wangwu的年齡,如果wangwu不存在,則返回-1
scala> map_NoChange.getOrElse("wangwu", -1)
res8: Int = -1
scala> map_Change.getOrElse("wangwu", -1)
res9: Int = -1
增加key,value對
// 新增一個學生:wangwu, 35
scala> map_NoChange + "wangwu"->36
res10: (String, Int) = (Map(zhangsan -> 30, lisi -> 40)wangwu,36)
scala> map_Change + "wangwu"->36
res11: (String, Int) = (Map(lisi -> 40, zhangsan -> 30)wangwu,36)
//上面這樣寫,好像錯了:
上面這樣就變成了: (map+"wangwu") -> 36 。 因為 -> 的優先級大於 +
結果就變成了一個 (String -> Int)的元組。 注意如下:
結果._1 = Map(lisi -> 40, zhangsan -> 30)wangwu 這是個字符串,非錶達式
結果._2 = 36 這是個Int
//上面好像這麼寫是錯的,寫成下面這樣就好了
scala> map_Change + ("wangwu"->36)
res16: scala.collection.mutable.Map[String,Int] = Map(lisi -> 40, zhangsan -> 30, wangwu -> 36)
scala> map_NoChange + ("wangwu"->36)
res17: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30, lisi -> 40, wangwu -> 36)
删除key
// 將lisi從可變映射中移除
scala> map_NoChange - "lisi"
res14: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 30)
scala> map_Change - "lisi"
res15: scala.collection.mutable.Map[String,Int] = Map(zhangsan -> 30)
切片(slice)
//使用和python一樣,但是寫法不一樣。
//scala的切片用slice
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-50h1rQdC-1658546420779)(scala.assets/image-20211124092843158.png)]
迭代器(iterator)
// scala針對每一類集合都提供了一個迭代器(iterator),用來迭代訪問集合。
使用迭代器遍曆集合
* 使用`iterator`方法可以從集合獲取一個迭代器
* 迭代器的兩個基本操作
* hasNext——查詢容器中是否有下一個元素
* next——返回迭代器的下一個元素,如果沒有,拋出NoSuchElementException
* 每一個迭代器都是有狀態的
* 迭代完後保留在最後一個元素的比特置
* 再次使用則拋出NoSuchElementException
* 可以使用while或者for來逐個返回元素
例:定義一個列錶,包含以下元素:1,2,3,4,5。 使用while循環和迭代器,遍曆打印該列錶
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)
scala> val ite = a.iterator
ite: Iterator[Int] = non-empty iterator
scala> while(ite.hasNext){
| println(ite.next)
| }
1
2
3
4
5
scala>
用for 便利迭代器
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)
scala> a
res0: List[Int] = List(1, 2, 3, 4, 5)
scala> val ite = a.iterator
ite: Iterator[Int] = non-empty iterator
scala> for (i <- ite)println(i)
1
2
3
4
5
scala>
函數式編程
//我們將來使用Spark/Flink的大量業務代碼都會使用到函數式編程。下面的這些操作是學習的重點。
- 遍曆(`foreach`)
- 映射(`map`)
- 映射扁平化(`flatmap`)
- 過濾(`filter`)
- 是否存在(`exists`)
- 排序(`sorted`、`sortBy`、`sortWith`)
- 分組(`groupBy`)
- 聚合計算(`reduce`)
- 折疊(`fold`)
遍曆(foreach)
//之前,學習過了使用for錶達式來遍曆集合。我們接下來將學習scala的函數式編程,使用`foreach`方法來進行遍曆、迭代。它可以讓代碼更加簡潔。
//注意,foreach是沒有返回值的哦。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-aimQskku-1658546449761)(scala.assets/image-20211030111532441.png)]
foreach執行過程
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-GScfMzdY-1658546449763)(scala.assets/image-20211030111623440.png)]
**例:**有一個列錶,包含以下元素1,2,3,4,請使用foreach方法遍曆打印每個元素
// 定義一個列錶
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
// 迭代打印
scala> a.foreach((x:Int)=>println(x))
使用類型推斷簡化函數定義:
/* 上述案例函數定義有點囉嗦,我們有更簡潔的寫法。因為使用foreach去迭代列錶,而列錶中的每個元素類型是確定的 * scala可以自動來推斷出來集合中每個元素參數的類型 * 創建函數時,可以省略其參數列錶的類型 */
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
// 省略參數類型
scala> a.foreach((x)=>println(x))
// 如果只有一個參數,那麼:括號都可以省略。
scala> a.foreach(x=>println(x))
使用下劃線來簡化函數定義:
/* 當函數參數,只在函數體中出現一次,而且函數體沒有嵌套調用時,可以使用下劃線來簡化函數定義 */
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
scala> a.foreach(println(_))
//函數的參數x 只在函數體中出現一次,才用_
//* 如果方法參數是函數,如果出現了下劃線,scala編譯器會自動將代碼封裝到一個函數中參數列錶也是由scala編譯器自動處理
映射(map)
//和python上的map玩法一樣的。
//集合的映射操作是將來在編寫Spark/Flink用得最多的操作,是我們必須要掌握的。因為進行數據計算的時候,就是一個將一種數據類型轉換為另外一種數據類型的過程。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-KEi0yDb2-1658546449763)(scala.assets/image-20211030114318070.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7O8fdESs-1658546449764)(scala.assets/image-20211030114357908.png)]
例: 對List中的每一個元素加1
scala> val a = List(1,2,3,4)
a: List[Int] = List(1, 2, 3, 4)
//寫法1
scala> a.map(x=>x+1)
res4: List[Int] = List(2, 3, 4, 5)
//寫法2
scala> a.map(_ + 1)
res4: List[Int] = List(2, 3, 4, 5)
//寫法3: 直接調用函數, 和方法1, 2 本質都是一樣的。
scala> val add = (x:Int, y:Int) => x + y
add: (Int, Int) => Int = $$Lambda$1142/1505791581@7d83321a
scala> val x = a.map(add(_,1))
x: List[Int] = List(2, 3, 4, 5)
映射扁平化(flatmap)
// 可以把flatMap,理解為先map,然後再flatten
- map是將列錶中的元素轉換為一個List
- flatten再將整個列錶進行扁平化
**例:**有一個包含了若幹個文本行的列錶:“hadoop hive spark flink flume”, “kudu hbase sqoop storm” 。 獲取到文本行中的每一個單詞,並將每一個單詞都放到列錶中。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JvqFwWw9-1658546449764)(scala.assets/image-20211030115625456.png)]
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 + flatten 做法
scala> a.map(_.split(" "))
res20: List[Array[String]] = List(Array(hadoop, hive, spark, flink, flume), Array(kudu, hbase, sqoop, storm))
scala> a.map(_.split(" ")).flatten
res21: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
// flatMap 做法
scala> a.flatMap(x => x.split(" "))
res24: List[String] = List(hadoop, hive, spark, flink, flume, kudu, hbase, sqoop, storm)
過濾(filter)
// 過濾符合一定條件的元素
例:1–10中,過濾出所以偶數
scala> val a = (1.to(10)).toList
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> a.filter(_ % 2 == 0)
res28: List[Int] = List(2, 4, 6, 8, 10)
是否存在(exists)
排序(sorted、sortBy、sortWith)
// 在scala集合中,可以使用以下幾種方式來進行排序
* sorted默認排序
* sortBy指定字段排序
* sortWith自定義排序
sorted默認排序
scala> List(3,1,2,9,7).sorted
res16: List[Int] = List(1, 2, 3, 7, 9)
sortBy指定字段排序
//根據傳入的函數轉換後,再進行排序
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ZHo938Jb-1658546449765)(scala.assets/image-20211030121406153.png)]
//實驗1: 注意要看明白,是神馬情况
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))
res30: List[String] = List(02 flume, 01 hadoop, 03 hive, 04 spark)
scala> a.sortBy(_.split(" ")(0))
res31: List[String] = List(01 hadoop, 02 flume, 03 hive, 04 spark)
//實驗2:
scala> b
res43: List[(String, Int)] = List((zhangsan,19), (lisi,55), (wangwu,22))
scala> b.sortBy(_._1)
res47: List[(String, Int)] = List((lisi,55), (wangwu,22), (zhangsan,19))
scala> b.sortBy(_._2)
res48: List[(String, Int)] = List((zhangsan,19), (wangwu,22), (lisi,55))
sortWith自定義排序
//自定義排序,根據一個函數來進行自定義排序
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-c2JuleVi-1658546449765)(scala.assets/image-20211030121440557.png)]
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)
/*使用下劃線簡寫上述案例*/
// 函數參數只在函數中出現一次,可以使用下劃線代替
scala> a.sortWith(_ < _).reverse
res19: List[Int] = List(6, 5, 4, 3, 2, 1)
分組(groupBy)
我們如果要將數據按照分組來進行統計分析,就需要使用到分組方法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MBDp51Vs-1658546449766)(scala.assets/image-20211030122607884.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sLffQJkY-1658546449766)(scala.assets/image-20211030122630438.png)]
/* 《總結 : groupBy 對數據進行分組》 1. 返回值為一個字典(Map) Map(key1 -> List(key1組數據完整值), key2 -> List(key2組數據完整值)) 例如: List("張三"->"男", "李四"->"女", "王五"->"男") .a.groupBy(_._2) 得到:Map(男 -> List((張三,男), (王五,男)), 女 -> List((李四,女))) */
例:對同學按照性別進行分組
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((李四,女)))
// 將分組後的映射轉換為性別/人數元組列錶
scala> res0.map(x => x._1 -> x._2.size)
res3: scala.collection.immutable.Map[String,Int] = Map(男 -> 2, 女 -> 1)
聚合計算(reduce)
//聚合操作,可以將一個列錶中的數據合並為一個。這種操作經常用來統計分析中
//reduce錶示將列錶,傳入一個函數進行聚合計算
/* reduce和reduceLeft效果一致,錶示從左到右計算 reduceRight錶示從右到左計算 */
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Do8H3RnF-1658546449767)(scala.assets/image-20211030123524634.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MS1YTuhc-1658546449767)(scala.assets/image-20211030123542043.png)]
**例:**求和
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
// 第一個下劃線錶示第一個參數,就是曆史的聚合數據結果
// 第二個下劃線錶示第二個參數,就是當前要聚合的數據元素
scala> a.reduce(_ + _)
res53: Int = 55
// 與reduce一樣,從左往右計算
scala> a.reduceLeft(_ + _)
res0: Int = 55
// 從右往左聚合計算
scala> a.reduceRight(_ + _)
res1: Int = 55
折疊(fold)
//fold與reduce很像,但是多了一個指定初始值參數
/* fold和foldLet效果一致,錶示從左往右計算 foldRight錶示從右往左計算 */
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Nvdw5HFK-1658546449768)(scala.assets/image-20211030123736570.png)]
**例:**定義一個列錶,包含以下元素:1,2,3,4,5,6,7,8,9,10 使用fold方法計算所有元素的和。
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
至此關於scala的初級入門學習已經完畢。
版權聲明
本文為[大寧哥]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2022/204/202207232106554040.html
邊欄推薦
猜你喜歡
隨機推薦
- 快速解决:Xshell拖不進去文件夾或者軟件包的問題
- RHCSA--文件內容瀏覽、cut、uniq、sort、.tr命令使用
- 信號完整性(SI)電源完整性(PI)學習筆記(三十二)電源分配網路(四)
- EasyGBS平臺出現錄像無法播放並存在RTMP重複推流現象,是什麼原因?
- 第七天筆記
- 【可視化調度軟件】上海道寧為SMB組織帶來NETRONIC下載、試用、教程
- 概率沉思錄:2.The quantitative rules
- 常用的鼠標事件和鍵盤事件
- C#:in、out、ref關鍵字
- GRE,MGRE的詳細了解;OSPF基礎配置知識
- Creo 9.0 如何快速修改CAD坐標系?
- 第五天筆記
- 强化學習——策略梯度理解點
- shell跑的時候需要的需要了解命令
- OKRK3399開發板預留I2C4掛載EEPROM
- 優化華為雲服務器采用Key登陸
- 第2章 基礎查詢與排序
- 【C語言】猜數字小遊戲+關機小程序
- 什麼是Per-Title編碼?
- @FeignClient使用詳細教程(圖解)
- Kettle實現共享數據庫連接及插入更新組件實例
- 基於matlab的CBOC信號調制解調仿真,輸出其相關性,功率譜以及頻偏跟踪
- VSCode 更新後與tab相關快捷鍵無法使用
- 後綴錶達式(暑假每日一題 4)
- 關於初始化page入參的設計思路
- Bean Validation核心組件篇----04
- 動態規劃背包問題之完全背包詳解
- 死磕遞歸1:遞推公式
- SQL報錯盲注詳解
- 工業物聯網中的時序數據
- 配置Gom引擎登錄器出現錯誤提示:沒有發現必備補丁文件!
- 【215】gin框架連接mysql數據庫
- go中的協程原理詳解
- 【JZOF】13機器人的運動範圍
- PCL:多直線擬合(RANSAC)
- 1259. 不相交的握手 動態規劃
- 基於FPGA的UART接口設計
- elk筆記25--快速體驗APM
- 能量原理與變分法筆記19:最小餘能原理+可能功原理
- 梅科爾工作室-小熊派開發筆記2


