柚子快報激活碼778899分享:開發(fā)語言 Scala學習
柚子快報激活碼778899分享:開發(fā)語言 Scala學習
Scala學習
scala介紹
Scala 是 Scalable Language 的簡寫,是一門多范式的編程語言
Scala是把函數(shù)式編程思想和面向對象編程思想結合的一種編程語言。
大數(shù)據(jù)計算引擎Spark由Scala編寫
scala特點
多范式:
面向對象函數(shù)式編程
兼容JAVA:
類庫調用互操作
語法簡潔:
代碼行短類型推斷抽象控制
靜態(tài)類型化:
可檢驗安全重構
支持并發(fā)控制:
強計算能力自定義其他控制結構
scala :OO(面向對象)+FP(函數(shù)式編程)
在面向對象編程中,我們把對象傳來傳去,那在函數(shù)式編程中,我們要做的是把函數(shù)傳來傳去,而這個,說成術語,叫做高階函數(shù)
在函數(shù)式編程中,函數(shù)是基本單位,,他幾乎被用作一切,包括最簡單的計算,甚至連變量都被計算所取代。在函數(shù)式編程中,變量只是一個名稱,而不是一個存儲單元,這是函數(shù)式編程與傳統(tǒng)的命令式編程最典型的不同之處。
scala和java編譯之后的class文件一樣
安裝使用scala
在idea中使用scala
1.在idea中增加scala插件支持scala的使用
2.安裝scala
①直接下載(scala官網下載)
②添加依賴下載
scala和java的編譯插件
使用scala
/**
* 寫scala可運行文件的注意事項
* 1、如果一個scala文件要運行,class要改成object
* 2、如果是class,就僅單純代表一個類,如果是object代表的是單例對象
* 3、scala語法中,一句話結束不需要加分號
* 4、scala文件中,可以無縫使用java中的類和方法
*/
object HelloWorld {
def main(args: Array[String]): Unit = {
println("hello world")
System.out.println("hhh") // java語法同樣可以運行
}
}
scala語法
1.變量與常量
變量:
在程序的運行過程中,其值可以發(fā)生改變的量,在scala中定義一個變量,需要使用一個關鍵詞:var
注意: 1、變量一旦定義,它的類型就確定,可以不用手動指定類型,根據(jù)賦的值自動推斷出類型 2、也可以手動的指定變量的數(shù)據(jù)類型,完整的寫法:var 變量名:數(shù)據(jù)類型 = 值
scala中的數(shù)據(jù)類型和java的數(shù)據(jù)類型對應關系:
java:scala:byteByteshortShortintIntlongLongfloatFloatdoubleDoublebooleanBooleancharChar
常量:
在程序的運行過程中,其值不能發(fā)生改變的量 在scala中定義一個常量,需要使用一個關鍵詞:val
定義一個變量a1,并賦值100
var a1 = 100 // 自動推斷出類型
println(a1)
println(a1.getClass) // 獲取變量的類型
// a1 = "你好" :string
println(a1)
a1 = 200 //可以改變值
println(a1)
//定義一個整數(shù)類型的變量a2,并賦值11
var a2: Int = 11 //給類型
println(a2)
println(a2.getClass)
println("=" * 50) // * 其實是一個函數(shù),底層是通過StringBuilder鏈接字符的
//定義一個整數(shù)常量a3,賦值300
val a3: Int = 300
println(a3)
2.字符串的使用
字符串:由若干個字符組成的序列
//正常使用雙引號構建字符串
var s1: String = "我是大帥哥!"
println(s1)
//使用三個一對雙引號構建長字符串
var sql1: String =
"""
|select
|*
|from
|students
|where age>18
|""".stripMargin
println(sql1)
String類和java是共同的一個字符串類,String類中的功能在scala中正常使用
// string類中的方法可以使用
var s3 = "hello,world,java,hadoop,scala"
// 數(shù)組
val arr1: Array[String] = s3.split(",")
// val arr1: Array[String] = s3 split "," 另一種寫法 只有一個參數(shù)去掉符號
println(arr1) // 打印的是地址值
//scala中的數(shù)組和java中的數(shù)組一樣,也是有索引的,也是從0開始的 注意是()不是java中的[]
println(arr1(0))
println(arr1(1))
println(arr1(2))
println(arr1(3))
println(arr1(4))
在scala中字符串是如何做拼接的?
1、使用+號拼接 這種拼接方式比較消耗性能2、使用StringBuilder3、前提:有一組序列,使用scala特有的函數(shù) mkString4、使用scala特有的字符串傳遞方式 s"${變量}" 底層就是使用StringBuilder方式拼接的
var q1: String = "hello"
var q2: String = "world"
var q3: String = "java"
var res1: String = q1 + "|" + q2 + "|" + q3
println(res1)// hello|world|java
val sb: StringBuilder = new StringBuilder()
sb.append(q1).append("-").append(q2).append("-").append(q3)
println(sb) //hello-world-java
val res3: String = arr1.mkString("&") // 數(shù)組方法
println(res3) //hello&world&java&hadoop&scala
val res4: String = s"${q1.toUpperCase}#${q2}#${q3}" //可以使用string的方法
println(res4) //HELLO#world#java
3.運算符
/*
* 運算符
* */
var x: Int = 3
var y: Int =4
println(x+y)
println(x-y)
println(x*y)
println(x/y)
println(x * 1.0/ y) // 整除
println(x%y)
4.條件語句
條件語句:
選擇語句: if
循環(huán)語句:for while
選擇語句: if
val sc = new Scanner(System.in)
print("請輸入年齡:")
val age : Int = sc.nextInt()
if(age>18){
println("成年了")
}else{
println("未成年")
}
循環(huán)語句
// for 循環(huán)遍歷數(shù)組
//創(chuàng)建一個數(shù)組
//數(shù)組:在內存中一塊連續(xù)固定大小的空間,有索引可以檢索數(shù)據(jù),查詢快,增刪慢
val arr1: Array[Int] = Array(1, 2, 3, 4, 5)
// 遍歷數(shù)組
// java的方法在這里行不通
// for(var i:Int = 0;i // println(arr1(i)) // } /** * 注意: * 1、在scala語言中,沒有++或者--的語法 i+=1 i= i+1 * 2、在scala語言中,不存在和java一樣的普通for循環(huán) * 3、scala中的for循環(huán)寫法不太一樣 */ for (i <- arr1){ println(i) } // while循環(huán)遍歷數(shù)組 var i :Int = 0 while (i println(arr1(i)) i +=1 } 需求:在控制臺中輸出10行hello world // while 循環(huán)實現(xiàn) var i:Int = 1 while (i<=10){ println("hello world") i+=1 } // 使用for循環(huán),指定循環(huán)的次數(shù) // 10次 包含10 for(e<-1 to 10){ println("hello world") } // 9次 不包含10 for(e<-1 until 10){ println("hello world") } 5.控制流程語句 注意:在scala中沒有break或者continue關鍵字 for (e <-1 to 5){ if(e == 2){ // continue 用不了 } println(e) } // break import scala.util.control.Breaks._ // scala中大部情況下,表示所有或者默認值或者占位符的時候,使用的是下劃線 for (e <-1 to 5){ if(e == 2){ break // 底層實現(xiàn)是一個函數(shù),拋出一個異常,終止程序運行 } println(e) } println("我是大帥哥") //Exception in thread "main" scala.util.control.BreakControl //后續(xù)代碼不會執(zhí)行 // break之后不停 繼續(xù)運行 使用breakable breakable{ for (e <-1 to 5){ if(e == 2){ break // 底層實現(xiàn)是一個函數(shù),拋出一個異常,終止程序運行 } println(e) } } println("我是大帥哥") // 1 我是大帥哥 遇到break 繼續(xù)運行 6.IO流 讀文件 /* * 對比java與scala * */ // 讀取一個文件內容 // java的方式讀取 val br = new BufferedReader(new FileReader("D:\\pypro\\Bigdt30\\scala\\data\\test.text")) var line : String = br.readLine() while(line != null){ println(line) line = br.readLine() } // scala中的讀取文件的方式 // Source.fromFil 底層是使用了字節(jié)輸入流讀取數(shù)據(jù)FileInputStream val bs: BufferedSource = Source.fromFile("D:\\\\pypro\\\\Bigdt30\\\\scala\\\\data\\\\test.text") // val lineIterator: Iterator[String] = bs.getLines() // while (lineIterator.hasNext){ // val s: String = lineIterator.next() // println(s) // } // for (e <- lineIterator) { // println(e) // } // 簡寫 for (e <- bs.getLines()) { println(e) } 寫文件 // java寫文件 val bw = new BufferedWriter(new FileWriter("scala/data/test1.text")) bw.write("哈哈哈哈哈") bw.newLine() bw.write("呵呵呵") bw.flush() // 純scala中沒有寫文件的方式 7.異常 與java中的很像 /** * scala中的異常和java的很像 */ try { // println(10/2) //除0異常 // val arr1: Array[Int] = Array(1, 2, 3, 4, 5) // println(arr1(5)) // 數(shù)組越界異常 // val br: BufferedReader = new BufferedReader(new FileReader("scala/data/words888.txt")) // 文件找不到異常 /** * 也可以手動的拋出異常 */ val sc = new Scanner(System.in) print("輸入除數(shù):") val cs: Int = sc.nextInt() if(cs!=0){ println(10/cs) }else{ throw new ArithmeticException("您輸入的除數(shù)是0") // 拋出異常 } }catch{ //類似于sql語句中case when case e:ArithmeticException=> // println("除0異常") e.printStackTrace() case e:ArrayIndexOutOfBoundsException=> println("數(shù)組越界異常") // case e:Exception=> 不確認的異常 // println("出現(xiàn)異常") case _ => // 任意一個異常 println("出現(xiàn)異常") }finally { //今后finally中的處理大部分情況下都與釋放資源有關 println("這是finally代碼塊") } println("hello world") 8.函數(shù)和方法 在不同的地方定義,稱呼不一樣 函數(shù):在object中定義的叫做函數(shù)方法:在class中定義的叫做方法 def main(args: Array[String]): Unit = {} def: 定義函數(shù)或者方法的關鍵字main: 是函數(shù)或者方法的名字,符合標識符的命名規(guī)則args: 函數(shù)形參的名字Array[String]: 參數(shù)的數(shù)據(jù)類型,是一個元素為字符串的數(shù)組=: 后面跟著函數(shù)體Unit: 等同于java中的void 表示無返回值的意思 def main(args: Array[String]): Unit = { //調用函數(shù) val res1: Int = add(3, 4) println(res1) //在main函數(shù)內也可以創(chuàng)建函數(shù) java中不行 但是要調用這個函數(shù)必須在定義后面 def plus(x: Int, y: Int): Int = { return x + y }// 證明:scala中的函數(shù)可以嵌套定義,函數(shù)中可以再定義函數(shù) //調用必須在定義之后 val res2: Int = plus(10, 20) println(res2) } //需求1:定義一個求兩個數(shù)之和的函數(shù),返回結果 // 在main函數(shù)之外 def add(a1: Int, b1: Int): Int = { return a1 + b1 } object Demo5Function { def main(args: Array[String]): Unit = { val res3: Int = add2(11, 22) // 報錯 println(res3) val d1 = new Demo1() //創(chuàng)建對象調用函數(shù) val res4: Int = d1.add2(11, 22) println(res4) } } // 函數(shù)或者方法必須定義在class或者object中 def add2(a1: Int, b1: Int): Int = { return a1 + b1 } class Demo1{ //這里叫方法,將來調用時需要創(chuàng)建該類的對象才可以調用 def add2(a1: Int, b1: Int): Int = { return a1 + b1 } } object Demo5Function { def main(args: Array[String]): Unit = { // 調用形式 //object中的函數(shù)可以使用類名調用,類似于靜態(tài)一樣 val res5: Int = Demo5Function.add(100, 200) println(res5) //調用形式2:object中的函數(shù)調用時,可以省略類名 val res6: Int = add(200, 300) println(res6) // 調用形式3 val res7: Int = fun1("1000") println(res7) //如果方法調用的函數(shù)只有一個參數(shù)的時候,可以將.和小括號用空格代替調用 val res8: Int = Demo5Function fun1 "1000" // "=" * 50 -> "=".*(50) println(res8) //如果定義的時候,沒有小括號,調用的時候,就不需要加小括號 show } def fun1(s:String): Int = { return s.toInt //定義格式1:如果函數(shù)有返回值,且最后一句話作為返回值的話,return關鍵字可以不寫 def add3(a1: Int, b1: Int): Int = { a1 + b1 } //定義格式2:如果函數(shù)體中只有一句實現(xiàn),那么大括號也可以不寫 def add4(a1: Int, b1: Int): Int = a1 + b1 //定義格式3:如果函數(shù)沒有參數(shù)的時候,小括號省略不寫 def show= println("好好學習,天天向上!") } } 函數(shù)的遞歸 /** * scala中的函數(shù)也可以遞歸 * 方法定義時,調用自身的現(xiàn)象 * * 條件:要有出口,不然就是死遞歸 */ def main(args: Array[String]): Unit = { //求階乘 5! val res1: Int = jieCheng(5) println(s"5的階乘是$res1") println(s"5的階乘是${Demo6Function jieCheng 5}") // 簡寫 } def jieCheng(number: Int): Int = { if (number == 1) { 1 } else { number * jieCheng(number - 1) } } 9.類(面向對象) val s1: Student = new Student() //好好學習,天天向上! /** * 可以在scala程序定義類 * 類:構造方法 成員方法 成員變量 * * 構造方法: * 1、在scala中構造方法的編寫和在java中不太一樣,類所擁有的大括號中都是構造代碼塊的內容 * 2、默認情況下,每一個類都應該提供一個無參的構造方法 * 3、構造方法可以有許多 */ //這就是一個構造方法 class Student{ println("好好學習,天天向上!") //理解為代碼塊 java中不行 } // 帶參構造 def main(args: Array[String]): Unit = { // val s1: Student = new Student("jack",18) val s2: Student = new Student("jack", 18, "男") println(s2) // 打印的是地址 需要tostring方法 //如果調用的是一個類的無參構造方法,new的時候小括號可以不用寫 val s3: Student2 = new Student2 s3.fun1() //也可以使用多態(tài)的方式創(chuàng)建對象 // val s4:Student2=new Student2 父類引用指向子類對象 // s4.fun1() 調用方法時 運行看左,編譯看右 此時父類中沒有此方法 報錯 val s4:Object = new Student("mike", 19, "男") println(s4.toString)// 考慮這種做法 } class Student(name: String, age: Int) { /** * 定義成員變量 */ val _name: String = name val _age: Int = age var _gender: String = _ // 這個下劃線,就表示將來會賦予默認值 /** * 構造方法也可以寫多個 */ def this(name: String, age: Int, gender: String) { this(name: String, age: Int) _gender = gender } /** * 也可以重寫方法 */ override def toString: String = { "姓名:" + _name + ", 年齡:" + _age + ", 性別:" + _gender } } class Student2{ def fun1()={ println("牛逼666") } } 與java創(chuàng)建類時一樣,定義成員變量,構造方法,getset方法,重寫tostring方法 非常麻煩 // caseclass /** * scala提供了一個非常好用的功能:樣例類 * 減少用戶創(chuàng)建類所編寫代碼量,只需要定義成員變量即可,自動擴充成員變量,構造方法,重寫toString方法 */ object Demo8CaseClass { def main(args: Array[String]): Unit = { val t1 = new Teacher("jack", 22, "打膠") println(t1) println(t1.name) println(t1.age) println(t1.like) t1.like = "敲代碼" println(t1)// 改變了 } } /** * 樣例類中的成員變量,編譯后默認是被jvm添加了final關鍵字,用戶是改變不了的 * 對于scala來說,默認是被val修飾的 * 如果將來想要被改變,定義的時候需要使用var進行修飾 */ case class Teacher(name:String,age:Int,var like:String) Apply def main(args: Array[String]): Unit = { val b1: Book = new Book() b1.apply() // 當作是一個普通的方法 } class Book{ def apply(): Unit = { println("hhh") } } def main(args: Array[String]): Unit = { Book() // 理解為伴生對象 可以直接調用object中的功能 } object Book{ def apply(): Unit = { println("hhh") } } def main(args: Array[String]): Unit = { val b1: Book = Book("中華上下五千年", 999) println(b1) } // object Book 是 object Book 的伴生對象 名字相同 object Book { def apply(name:String,price:Int): Book = { new Book(name,price) } } class Book(name: String, price: Int) { val _name: String = name val _price: Int = price override def toString: String = "書名:" + _name + ", 價格:" + _price } 10.函數(shù)式編程 面向對象與函數(shù)式編程的區(qū)別: 面向對象編程:將對象當作參數(shù)一樣傳來傳去1、對象可以當作方法參數(shù)傳遞2、對象也可以當作方法的返回值返回當看到類,抽象類,接口的時候,今后無論是參數(shù)類型還是返回值類型,都需要提供對應的實現(xiàn)類對象 // 是一個參數(shù)為字符串類型,返回值是整數(shù)類型的函數(shù) def fun1(s: String): Int = { s.toInt + 1000 } val res1: Int = fun1("1000") println(res1) 面向函數(shù)式編程:將函數(shù)當作參數(shù)一樣傳來傳去1、函數(shù)A當作函數(shù)B的參數(shù)進行傳遞2、函數(shù)A當作函數(shù)B的返回值返回在scala中,將函數(shù)也當作一個對象,對象就有類型函數(shù)在scala也有類型的說法參數(shù)類型=>返回值類型 //定義變量的方式,定義一個函數(shù) //將函數(shù)當作對象,賦值給類型是函數(shù)類型的變量,將來可以直接通過變量調用函數(shù) val fun2: String => Int = fun1 val res2: Int = fun2("2000") println(res2) // 3000 函數(shù)A作為函數(shù)B的參數(shù)定義 本質上是將函數(shù)A的處理邏輯主體傳給了函數(shù)B,在函數(shù)B中使用這個處理邏輯 // f: String => Int 相當于函數(shù)A // fun3 相當于函數(shù)B //定義 函數(shù)主體 def fun3(f: String => Int): Int = { val a1: Int = f("1000") a1 + 3000 } // 定義一個函數(shù) def show1(s:String): Int = { s.toInt } //調用 val res1: Int = fun3(show1) // show1->f println(res1) // 4000 def show2(s: String): Int = { s.toInt+11111 } val res2: Int = fun3(show2) println(res2)// 15111 //定義一個函數(shù)fun1, 函數(shù)的參數(shù)列表中,既有正常的類型參數(shù),也有函數(shù)類型的參數(shù) def fun1(s: String, f: String => Int): Int = { val a1: Int = f(s) a1 + 1000 } def show1(s: String): Int = { s.toInt } def show2(s: String): Int = { s.toInt + 1111 } // ..... val res1: Int = fun1("2000", show2) // 可以傳不同的函數(shù) 很麻煩 使用lambda簡寫 println(res1) //使用lambda表達式改寫函數(shù)作為參數(shù)傳遞的調用形式 直接把函數(shù)邏輯寫在后面 fun1("2000", (s: String) => s.toInt) fun1("2000", (s: String) => s.toInt+1000) //在scala中,數(shù)據(jù)類型可以自動類型推斷 fun1("2000", s => s.toInt+1000) //如果當作參數(shù)的函數(shù)的參數(shù)只在函數(shù)主體使用了一次,那么可以使用_代替 fun1("2000", _.toInt+1000) 應用:遍歷數(shù)組 def main(args: Array[String]): Unit = { val arr1: Array[Int] = Array(11, 22, 33, 44, 55) // 遍歷 太麻煩 使用foreach函數(shù) // for (e <- arr1) { // println(e) // } // def fun1(i: Int): Unit = { // println(i*2) // } //def foreach[U](f: A => U): Unit //foreach函數(shù)需要一個參數(shù)和數(shù)組元素一樣類型的類型,返回值是Unit的函數(shù) //foreach函數(shù)的主要作用是將調用該方法的序列中的元素,依次取出傳遞給后面的函數(shù)進行處理 arr1.foreach(fun1) // scala自帶的一個函數(shù) // def println(x: Any) = Console.println(x) // Any可以接收任意的數(shù)據(jù)類型元素 arr1.foreach(println) } 函數(shù)當作返回值返回 /** * fun1: 參數(shù)是String類型,返回值是一個函數(shù)(參數(shù)是String類型,返回值是Int) */ // 定義返回值是函數(shù)的函數(shù)方式1: def fun1(s1: String): String => Int = { def show(s: String): Int = { // 要返回的函數(shù) s.toInt + s1.toInt } show } // 調用函數(shù)的返回值是函數(shù)的方式1: val resFun1: String => Int = fun1("1") // 把函數(shù)作為對象賦給一個變量 show-> resFun1 val res1: Int = resFun1("1000") println(res1) // //調用方式2: // val res2: Int = fun1("1")("1000") // println(res2) 什么是函數(shù)柯里化? 1、本身是一個數(shù)學界的一個名詞,本意是原來一次傳遞多個參數(shù),現(xiàn)在被改成了可以分開傳遞的形式,這種做法叫做柯里化2、在scala中體現(xiàn)柯里化,指的是函數(shù)的返回值也是一個函數(shù),將來調用時參數(shù)可以分開傳遞。3、提高了程序的靈活性和代碼復用性4、在scala中也可以通過偏函數(shù)實現(xiàn)參數(shù)分開傳遞的功能 //定義方式2(是方式1的簡化寫法): /** * 方式2這種將參數(shù)分開定義,今后調用時可以分開傳遞,這種做法,在scala中叫做函數(shù)柯里化 * */ def fun1(s1: String)(s: String): Int = { s.toInt + s1.toInt } //函數(shù)柯里化: val resFun1: String => Int = fun1("1") val r1: Int = resFun1("11") println(r1) val r2: Int = resFun1("12") println(r2) val r3: Int = resFun1("13") println(r3) // 調用方法和方式一相同 def function1(s1: String, s2: String): Int = { // 返回值類型不是函數(shù) s1.toInt + s2.toInt } /** * 偏函數(shù) * 分開傳遞 */ val f1: String => Int = function1("1", _) // 加_得到一個函數(shù) val res1: Int = f1("1000") val res2: Int = f1("2000") val res3: Int = f1("3000") println(s"res1:$res1,res2:$res2,res3:$res3") 11.集合 java中的ArrayList def main(args: Array[String]): Unit = { val list1: util.ArrayList[Int] = new util.ArrayList[Int]() // 創(chuàng)建ArrayList list1.add(11) list1.add(22) list1.add(33) list1.add(44) //scala中的for循環(huán),只能遍歷scala中的序列,無法遍歷java的序列 // for (e <- list1) { 無法使用 // } // 使用while循環(huán)遍歷 var i = 0 while (i < list1.size()) { println(list1.get(i)) i += 1 } scala的集合: List: 元素有序,且可以發(fā)生重復,長度固定的Set: 元素無序,且唯一,長度固定的Map: 元素是鍵值對的形式,鍵是唯一的Tuple: 元組,長度是固定的,每個元素的數(shù)據(jù)類型可以不一樣 // list //創(chuàng)建了一個空集合 val list1: List[Nothing] = List() val list2: List[Int] = List(34, 11, 22, 11, 33, 44, 55, 22, 75, 987, 1, 12, 34, 66) // 1.獲取List集合的長度 println(list2.size) println(list2.length) //2.通過索引下標獲取元素 println(list2(0)) println(list2(1)) //3.scala推薦獲取第一個元素的方式是調用head函數(shù) 最后一個元素調用last println(list2.head) println(list2.last) //4.根據(jù)指定的分隔符拼接元素 println(list2.mkString("|")) //5.反轉 val resList1: List[Int] = list2.reverse println(s"list2:$list2") println(s"resList1:$resList1") //6.去重 val resList2: List[Int] = list2.distinct //返回一個新的集合 println(s"list2:$list2") println(s"resList2:$resList2") //7.去掉第一個元素 tail val resList3: List[Int] = list2.tail // 除去第一個,其余的元素返回一個新的集合 println(s"list2:$list2") println(s"resList3:$resList3") //8.取數(shù)(前幾個) val resList4: List[Int] = list2.take(5) // 從左向右取元素,取若干個 println(s"list2:$list2") println(s"resList4:$resList4") //9.取數(shù)(靠右邊的) val resList5: List[Int] = list2.takeRight(5) //取右邊的幾個,組成新的集合 println(s"list2:$list2") println(s"resList5:$resList5") //10.從第一個判斷取數(shù)據(jù),直到不符合條件停止 val resList6: List[Int] = list2.takeWhile((e: Int) => e % 2 == 0) println(s"list2:$list2") println(s"resList6:$resList6") //11.求和 val res1: Int = list2.sum // 元素必須是數(shù)值 println(s"集合中的元素和為:$res1") //12.最值 val res2: Int = list2.max println(s"集合中的元素最大值為:$res2") //13.遍歷集合 for (e <- list2) { println(e) } //list的高階函數(shù) //foreach: 將集合中的元素依次取出傳入到后面的函數(shù)中 // 注意:沒有返回值的,要么就輸出,要么就其他方式處理掉了 //def foreach[U](f: A => U) list2.foreach((e: Int) => println(e)) // 簡寫 list2.foreach(println) //需求1:使用foreach求出集合中偶數(shù)的和 var ouSum = 0 var jiSum = 0 list2.foreach((e: Int) => { if (e % 2 == 0) { ouSum += e } else { jiSum += e } }) println(s"集合中偶數(shù)之和為:$ouSum") println(s"集合中奇數(shù)之和為:$jiSum") // map: 依次處理每一個元素,得到一個新的結果,返回到一個新的集合中 val list3: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) //需求2:將集合中的每一個元素*2 val resList7: List[Int] = list3.map((e: Int) => e * 2) println(s"list3:$list3") println(s"resList7:$resList7") //filter: 保留符合條件的元素 val list4: List[Int] = List(4, 7, 9, 10, 12, 11, 14, 9, 7) val resList8: List[Int] = list4.filter((e: Int) => e % 2 == 0) println(s"list4:$list4") println(s"resList8:$resList8") // sortBy: 排序 // sortWith: 兩個數(shù)之間的關系排序 val resList9: List[Int] = list4.sortBy((e: Int) => -e) println(s"list4:$list4") println(s"resList9:$resList9") val resList10: List[Int] = list4.sortWith((x: Int, y: Int) => x > y) println(s"list4:$list4") println(s"resList10:$resList10") //flatMap: 扁平化 val list5: List[String] = List("hello|world|java", "hello|hadoop|flink", "scala|spark|hadoop") val resTmp1: List[String] = list5.flatMap((e: String) => e.split("\\|")) resTmp1.foreach(println) // groupBy: 分組 val list6: List[String] = List("hello", "world", "java", "hadoop", "flink", "java", "hadoop", "flink", "flink", "java", "hadoop", "flink", "java", "hadoop", "hello", "world", "java", "hadoop", "hello", "world", "java", "hadoop") val map: Map[String, List[String]] = list6.groupBy((e: String) => e) // 按照元素分組 for (e <- map) { println(e) } // set //set集合:scala中的Set集合也是不可變的,除了排序相關的函數(shù)以外,List集合有的高階函數(shù),Set集合也有 無序 // 創(chuàng)建兩個set集合 val set1: Set[Int] = Set(1, 4, 3, 6, 5) val set2: Set[Int] = Set(3, 6, 5, 7, 8) // 求交集 // val resSet1: Set[Int] = set1.&(set2) // val resSet1: Set[Int] = set1 & set2 val resSet1: Set[Int] = set1.intersect(set2) println(s"set1: ${set1}") println(s"set2: ${set2}") println(s"交集: ${resSet1}") //(5,6,3) //求并集 // val resSet2: Set[Int] = set1.|(set2) val resSet2: Set[Int] = set1 | set2 println(s"set1: ${set1}") println(s"set2: ${set2}") println(s"并集: ${resSet2}") //求差集 // val resSet3: Set[Int] = set1.&~(set2) val resSet3: Set[Int] = set1 &~ set2 println(s"set1: ${set1}") println(s"set2: ${set2}") println(s"差集: ${resSet3}") //set集合和list集合相互轉換 toset tolist val list1: List[Int] = List(11, 22, 33, 44, 55, 11, 22, 44, 88, 33, 44, 99, 11, 22, 55) //List->Set val resSet4: Set[Int] = list1.toSet println(s"list1:${list1}") println(s"resSet4:${resSet4}") println("=" * 50) //Set->List val list2: List[Int] = resSet4.toList.sortBy((e:Int)=>e) println(s"list1:${list1}") println(s"resSet4:${resSet4}") println(s"list2:${list2}") //mutable /** * 通過觀察api發(fā)現(xiàn),不可變的集合是屬于scala.collection.immutable包下的 * 如果將來想要使用可變的集合,就要去scala.collection.mutable包下尋找 */ //創(chuàng)建一個可變的List集合 val listBuffer1: ListBuffer[Int] = new ListBuffer[Int] // 向集合中添加元素 listBuffer1.+=(11) listBuffer1.+=(22) listBuffer1.+=(33) listBuffer1.+=(11) listBuffer1.+=(55) listBuffer1.+=(22) listBuffer1.+=(33) listBuffer1.+=(66) listBuffer1.+=(33) println(listBuffer1) //使用函數(shù)獲取元素 同list集合 list集合的功能可變集合都能調用 println(listBuffer1(2)) println(listBuffer1.head) println(listBuffer1.last) // 刪除元素 listBuffer1.-=(33) //從左向右找元素,只會刪除第一次找到的 //批量添加元素 listBuffer1.+=(100,220,300,400) // 直接添加一個集合進去 val list1: List[Int] = List(99, 88, 77) listBuffer1.++=(list1) // 可變的set集合 功能同set集合 val hashSet1: mutable.HashSet[Int] = new mutable.HashSet[Int]() val set1: hashSet1.type = hashSet1.+=(1, 2, 3, 4, 5, 7, 1, 2, 3, 1, 6, 5) println(set1) // Tuple //大小,值是固定的,根據(jù)創(chuàng)建的類來定,每個元素的數(shù)據(jù)類型可以是不一樣,最高可以創(chuàng)建存儲22個元素的元組 // 不可變 保護信息 // 創(chuàng)建一個5元組 val t1: (Int, String, String, Int, String) = Tuple5(1001, "jack", "男", 17, "學習") // case class Student1(id: Int, name: String, age: Int, like: String) val s2: Student1 = new Student1(1002, "mike", 18, "看劇") val t2: (Int, Student1) = Tuple2(1002, s2) println(t2._2.name) //map //創(chuàng)建Map集合 元素是鍵值對形式 //鍵是唯一的,鍵一樣的時候,值會被覆蓋 val map1: Map[Int, String] = Map((1001, "張三"), (1002, "李四"), (1003, "王五"), (1001, "趙六"), 1005 -> "老劉") println(map1) //可以根據(jù)鍵獲取值 // println(map1(1006)) // 小括號獲取值,鍵不存在報錯 // println(map1.get(1006)) // get函數(shù)獲取,鍵不存在,返回None println(map1.getOrElse(1006, 0)) //根據(jù)鍵獲取值,若鍵不存在,返回提供的默認值,默認值的類型可以是任意數(shù)據(jù)類型 val keys: Iterable[Int] = map1.keys // 獲取所有的鍵,組成一個迭代器 for (e <- keys) { println(e) } val values: Iterable[String] = map1.values // 獲取所有的值,組成一個迭代器 for (e <- values) { println(e) } // 遍歷map //遍歷Map集合第一種方式,先獲取所有的鍵,根據(jù)鍵獲取每個值 val keys2: Iterable[Int] = map1.keys // 獲取所有的鍵,組成一個迭代器 for (e <- keys2) { val v: Any = map1.getOrElse(e, 0) println(s"鍵:${e}, 值:${v}") } //遍歷Map集合第二種方式 for (kv <- map1) { // 直接遍歷map集合,得到每一個鍵值對組成的元組 println(s"鍵:${kv._1}, 值:${kv._2}") } //遍歷Map集合第三種方式 map1.foreach((kv: (Int, String)) => println(s"鍵:${kv._1}, 值:${kv._2}")) 集合的應用案例 WordCount: def main(args: Array[String]): Unit = { //1、讀取數(shù)據(jù)文件,將每一行數(shù)據(jù)封裝成集合的元素 val lineList: List[String] = Source.fromFile("scala/data/words.txt").getLines().toList println(lineList) //2、將每一行數(shù)據(jù)按照|切分,并且進行扁平化 val wordsList: List[String] = lineList.flatMap((line: String) => line.split("\\|")) println(wordsList) //3、根據(jù)元素進行分組 val wordKV: Map[String, List[String]] = wordsList.groupBy((e: String) => e) println(wordKV) /** * List((world,8), (java,11),...) */ val wordCount: Map[String, Int] = wordKV.map((kv: (String, List[String])) => { val word: String = kv._1 val count: Int = kv._2.size (word, count) }) println("="*50) val resultList: List[(String, Int)] = wordCount.toList resultList.foreach(println) println("="*50) // /** // * 使用鏈式調用的方式簡寫 // */ // Source.fromFile("scala/data/words.txt") // .getLines() // .toList // .flatMap((line:String)=>line.split("\\|")) // .groupBy((e:String)=>e) // .map((kv: (String, List[String])) => { // val word: String = kv._1 // val count: Int = kv._2.size // (word, count) // }) // .toList // .foreach(println) } } 12.JDBC import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet} /** * jdbc的鏈接步驟 * 1、注冊驅動 * 2、創(chuàng)建數(shù)據(jù)庫鏈接對象 * 3、創(chuàng)建數(shù)據(jù)操作對象 * 4、執(zhí)行sql語句 * 5、如果第4步是查詢的話,分析查詢結果 * 6、釋放資源 */ object Demo20JDBC { def main(args: Array[String]): Unit = { //1、注冊驅動 Class.forName("com.mysql.jdbc.Driver") //2、創(chuàng)建數(shù)據(jù)庫鏈接對象 //jdbc:數(shù)據(jù)庫名://host:port/數(shù)據(jù)庫?xxx=xxx&xxx=xxx val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/Y1?useUnicode=true&characterEncoding=UTF-8&useSSL=false", "root", "123456") //3、創(chuàng)建數(shù)據(jù)操作對象 val preparedStatement: PreparedStatement = conn.prepareStatement("select id,name,age,gender,clazz from student where clazz=?") //4、執(zhí)行sql語句 // 防止sql注入 // preparedStatement.setInt(1,23) preparedStatement.setString(1, "理科二班") val resultSet: ResultSet = preparedStatement.executeQuery() //5、如果第4步是查詢的話,分析查詢結果 while (resultSet.next()){ val id: Int = resultSet.getInt("id") val name: String = resultSet.getString("name") val age: Int = resultSet.getInt("age") val gender: String = resultSet.getString("gender") val clazz: String = resultSet.getString("clazz") println(s"學號:$id, 姓名:$name, 年齡:$age, 性別:$gender, 班級:$clazz") } //6、釋放資源 conn.close() } } 13.JSON 導入依賴 import scala.io.Source import com.alibaba.fastjson.{JSON, JSONArray, JSONObject} def main(args: Array[String]): Unit = { val lineList: List[String] = Source.fromFile("scala/data/stu.json").getLines().toList // 拼起來 val jsonStr: String = lineList.mkString("\r\n") //使用fastjson包中的JSON類,將一個字符串轉成json對象 //轉成json對象之后,可以通過鍵獲取值 //parseObject 將整體轉成一個json格式數(shù)據(jù) val jsonObj1: JSONObject = JSON.parseObject(jsonStr) // 鍵獲取值 val s1: String = jsonObj1.getString("student_list") //parseArray將一個"[{},{}]"變成一個元素是json對象的數(shù)組 val jSONArray: JSONArray = JSON.parseArray(s1) // 遍歷數(shù)組 var i = 0 while (i < jSONArray.size()) { val obj1: JSONObject = jSONArray.getJSONObject(i) val name: String = obj1.getString("name") val like: String = obj1.getString("like") println(s"${name}的愛好是${like}") i += 1 } } 14.scala,java集合的轉換 def main(args: Array[String]): Unit = { //創(chuàng)建一個java中的集合 val array1: util.ArrayList[Int] = new util.ArrayList[Int]() array1.add(11) array1.add(22) array1.add(33) array1.add(66) array1.add(55) array1.add(44) println(array1) /** * 將java中的集合轉成scala中的集合 * * java中的集合本來是沒有轉換scala的功能,需要導入隱式轉換 * scala中的導包,可以在任意地方 * */ import scala.collection.JavaConverters._ val list1: List[Int] = array1.asScala.toList println(list1) /** * scala中的集合轉java的集合 */ val list2: util.List[Int] = list1.asJava println(list2) } } 15.模式匹配 模式匹配,可以幫助我們開發(fā)的時候,減少代碼量,讓邏輯看起來更加清晰,以及可以避免一些異常 語法: 表達式 match { case 值|[變量名:類型]|元組|數(shù)組|對象=> 匹配成功執(zhí)行的語句 case xxx=> xxx _ xxx=> xxx } * 模式匹配中,如果沒有對應的匹配,那么就報錯!!! /** * 可以匹配變量值 */ var i: Int = 100 i match { case 20 => println("該值是20") case 50 => println("該值是50") // case 100=>println("該值是100") case _ => println("其他值") } // 其他值 /** // * 匹配數(shù)據(jù)類型 // */ var flag1: Any = true flag1 match { case _: Int => println("是Int類型") case _: Boolean => println("是boolean類型") } /** // * 匹配元組 // */ val t1: (Int, String, Int) = Tuple3(1001, "張三", 18) t1 match { case (a1: Int, b1: String, c1: Int) => println(s"學號:$a1, 姓名:$b1, 年齡:$c1") } // // /** // * 匹配數(shù)組 // */ val array: Array[Any] = Array(1001, "李四", "男", 18, "理科一班") array match { case Array(id: Int, name: String, gender: String, age: Int, clazz: String) => println(s"學號:$id, 姓名:$name, 性別:$gender, 年齡:$age, 班級:$clazz") } 模式匹配的應用: /** * 模式匹配的應用1:避免異常 * */ val map1: Map[Int, String] = Map((1001, "張三"), (1002, "李四")) // val res1: Option[String] = map1.get(1001) // Some("張三") // .get 方法獲取值 // println(res1.get) // val res1: Option[String] = map1.get(1003) // println(res1.get) val sc: Scanner = new Scanner(System.in) println("請輸入要查詢的鍵:") val key: Int = sc.nextInt() map1.get(key) match { case Some(a: Any) => println(s"${key}鍵對應的值為$a") case None => println(s"${key}鍵不存在!") }// 輸入1001 輸出 1001鍵對應的值為張三 // 輸入1003 輸出 1003鍵不存在 /** * 模式匹配的應用2:簡化代碼 *students.txt 部分數(shù)據(jù): * 1500100066,惠耘濤,22,男,文科三班 * 1500100067,廣浦澤,22,男,文科五班 * 1500100068,宣南蓉,23,女,理科一班 */ val stuList: List[String] = Source.fromFile("scala/data/students.txt").getLines().toList val stuArrayList: List[Array[String]] = stuList.map((line: String) => line.split(",")) // 不用模式匹配 stuArrayList.map((e:Array[String])=>{ val id: String = e(0) val name: String = e(1) val age: String = e(2) val gender: String = e(3) val clazz: String = e(4) (id, name, gender, age, clazz) }).foreach(println) // 使用模式匹配 stuArrayList.map{ case Array(id: String, name: String, gender: String, age: String, clazz: String)=> (id, name, gender, age, clazz) }.foreach(println) 16.隱式轉換 scala中的隱式轉換: 1、scala中的隱式轉換,本質上就是將一個類型轉換成另一個類型去使用另一個類型中的功能 2、scala中的隱式轉換分為3種:隱式轉換函數(shù),隱式轉換類,隱式轉換變量 3、隱式轉換函數(shù),在使用隱式轉換函數(shù)返回值類型的功能的時候,可以自動的將參數(shù)的類型轉成返回值類型進行使用 4、隱式轉換類,可以自動的將構造方法的參數(shù)類型轉成類的類型,將來可以直接使用構造方法中的類型調用類中的方法 5、隱式轉換變量,配合函數(shù)定義中的隱式轉換參數(shù)使用, ? 將來調用函數(shù)的時候,可以不用傳入隱式轉換參數(shù)的值,自動使用對應類型的隱式轉換變量 ? 當然,也可以手動傳入具體的值給隱式轉換參數(shù)。 // 隱式轉換函數(shù) // 將一個A類型將來會自動地轉換成另一個B類型,類型可以式基本數(shù)據(jù)類型,也可以是引用數(shù)據(jù)類型 var i:String = "100" //顯式轉換 val res1: Int = i.toInt // 定義一個函數(shù) def fun1(s: Int): Int = { return s + 1000 } //調用函數(shù) println(fun1(100)) println(fun1(200)) println(fun1("300".toInt)) // 定義隱式轉換函數(shù) //需求:調用fun1函數(shù),就只傳字符串,不會報錯 //在需要返回值類型的功能的時候,自動地根據(jù)已有隱式轉換函數(shù)將參數(shù)的類型轉成返回值的類型 // 參數(shù)類型和返回值類型相同時,盡管函數(shù)體不一樣,也是重復的隱式函數(shù) implicit def implicitFun1(s: String): Int = { return Integer.parseInt(s) } //調用函數(shù) println(fun1(100)) println(fun1(200)) println(fun1("300")) // 不報錯,有結果 // 讀文件時的隱式轉換 將字符串自動轉換為BufferedSource類 object Demo11 { implicit def implicitFun3(s: String): BufferedSource = Source.fromFile(s) implicit def implicitFun1(s: String): Int = Integer.parseInt(s) } import com.shujia.jichu.Demo11._ val stuList: List[String] = "scala/data/students.txt".getLines().toList val scoreList: List[String] = "scala/data/scores.txt".getLines().toList println("1000" + 500) // 1000500 // 優(yōu)先使用字符串自身的+拼接功能,做字符串拼接 println("1000" - 500) // 500 // 字符串中沒有-減法功能,自動使用隱式轉換中的函數(shù),將字符串轉成數(shù)字做減法 println("2000" - 500) // 1500 // 字符串中沒有-減法功能,自動使用隱式轉換中的函數(shù),將字符串轉成數(shù)字做減法 /** * 隱式轉換類 */ def main(args: Array[String]): Unit = { // 正常做法 // 創(chuàng)建對象,使用函數(shù) val demo1 = new Demo12("scala/data/students.txt") val stuList: List[String] = demo1.show1() // 定義隱式轉換類之后 字符串自動轉換為對象 val stuList: List[String] = "scala/data/students.txt".show1() } // 定義一個隱式轉換類 讀取文件信息 //`implicit' modifier cannot be used for top-level objects 不能寫在object外面 //implicit class Demo12(path: String) { //implicit使用的地方,不能超過object作用域 implicit class Demo12(path: String) { def show1(): List[String] = { Source.fromFile(path).getLines().toList } /** * 隱式轉換變量 */ def main(args: Array[String]): Unit = { // 之前沒有定義過讀取文件編碼,是因為 def fromFile(name: String)(implicit codec: Codec): BufferedSource 存在隱式轉換參數(shù)codec 默認utf-8 可以手動修改 Source.fromFile("scala/data/students.txt")(Codec("GBK")).getLines().toList //定義一個隱式轉換參數(shù) def fun1(a1: Int)(implicit a2: Int): Int = a1 + a2 //定義一個隱式轉換變量 implicit var i1: Int = 1000 // a2可以不用傳,尋找Int類型的變量,直接使用默認值 val res1: Int = fun1(100) println(res1) //1100 } scala進階應用: 階段一 基于學生、分數(shù)、科目數(shù)據(jù)使用Scala語言完成下面的練習 中括號為最終要求輸出的格式 題目較為基礎 1.統(tǒng)計班級人數(shù) [班級,人數(shù)] 2.統(tǒng)計學生的總分 [學號,學生姓名,學生年齡,總分] 階段二 數(shù)據(jù)同階段二一樣 題目難度偏大 1、統(tǒng)計年級排名前十學生各科的分數(shù) [學號, 姓名,班級,科目,分數(shù)] 2、統(tǒng)計總分大于年級平均分的學生 [學號,姓名,班級,總分] 3、統(tǒng)計每科都及格的學生 [學號,姓名,班級,科目,分數(shù)] 4、統(tǒng)計每個班級的前三名 [學號,姓名,班級,分數(shù)] 5、統(tǒng)計偏科最嚴重的前100名學生 [學號,姓名,班級,科目,分數(shù)] 數(shù)據(jù)準備: 部分數(shù)據(jù)截圖: students.txt score.txt subject.txt import scala.collection.immutable import scala.io.Source object HomeWork { //定義一些變量,樣例類,為后續(xù)的開發(fā)做準備 /** * 定義一些樣例類 類似于java的封裝 */ private case class Student(id: String, name: String, age: Int, gender: String, clazz: String) private case class Score(id: String, subject_id: String, score: Int) private case class Subject(subject_id: String, subject_name: String, subject_score: Int) /** * 定義三個存儲三個不同對象的List集合 */ private var stuList: List[Student] = _ private var scoreList: List[Score] = _ private var subjectList: List[Subject] = _ /** * 定義一些map集合 * stuInfoMap (stu.id, stu.name + "," + stu.clazz) * subNameMap (subject.subject_id, subject.subject_name) * subScoreMap (subject.subject_id, subject.subject_score) */ private var stuInfoMap: Map[String, String] = _ private var subNameMap: Map[String, String] = _ private var subScoreMap: Map[String, Int] = _ //初始化變量 private def loadData(): Unit = { //讀取學生數(shù)據(jù) stuList = "scala/data/students.txt".load() .map { case Array(id: String, name: String, age: String, gender: String, clazz: String) => Student(id, name, age.toInt, gender, clazz) } //讀取成績數(shù)據(jù) scoreList = "scala/data/score.txt".load() .map { case Array(id: String, subject_id: String, score: String) => Score(id, subject_id, score.toInt) } //讀取科目數(shù)據(jù) subjectList = "scala/data/subject.txt".load() .map { case Array(subject_id: String, subject_name: String, subject_score: String) => Subject(subject_id, subject_name, subject_score.toInt) } //處理三個map集合 //stuInfoMap 存儲了學生的學號為鍵,姓名和班級作為值 stuInfoMap = stuList.map((stu: Student) => (stu.id, stu.name + "," + stu.clazz)).toMap subNameMap = subjectList.map((sub: Subject) => (sub.subject_id, sub.subject_name)).toMap subScoreMap = subjectList.map((sub: Subject) => (sub.subject_id, sub.subject_score)).toMap } /** * 根據(jù)學號集合打印【學號,姓名,班級,科目,分數(shù)】 */ private def printStudentInfoWithId(ids: List[String]): Unit = { // 從總的學生成績信息中過濾出來 scoreList.filter((sco: Score) => ids.contains(sco.id)) .map { case Score(id: String, subject_id: String, score: Int) => { //根據(jù)學號,查找姓名和班級 stuInfoMap val nameWithClazz: String = stuInfoMap.getOrElse(id, "查無此人") //根據(jù)科目編號,查找科目的名字 subNameMap val subject_name: String = subNameMap.getOrElse(subject_id, "無此科目") s"[$id,$nameWithClazz,$subject_name,$score]" } }.foreach(println) } /** * 統(tǒng)計班級人數(shù) [班級,人數(shù)] */ private def xuQiu1(): Unit = { stuList.groupBy((stu: Student) => stu.clazz) .map((kv: (String, List[Student])) => { s"[${kv._1},${kv._2.size}]" }).foreach(println) } /** * 統(tǒng)計學生的總分 [學號,學生姓名,學生年齡,總分] */ private def xuQiu2(): Unit = { val stringToInt: Map[String, Int] = scoreList.groupBy((sco: Score) => sco.id) .map((kv: (String, List[Score])) => { (kv._1, kv._2.map(_.score).sum) }) val ids: List[String] = stringToInt.map { case (id: String, _: Int) => id }.toList stuList.filter((stu: Student) => ids.contains(stu.id)) .map((stu: Student) => { val sumScore: Int = stringToInt.getOrElse(stu.id, 0) s"[${stu.id},${stu.name},${stu.age},$sumScore]" }).foreach(println) } /** * 統(tǒng)計年級排名前十學生各科的分數(shù) [學號,姓名,班級,科目,分數(shù)] */ private def xuQiu3(): Unit = { val ids: List[String] = scoreList.groupBy((s: Score) => s.id) // 按照學號進行分組 .map((kv: (String, List[Score])) => { (kv._1, kv._2.map(_.score).sum) // 求每個學生的總分 }) .toList .sortBy(-_._2) .take(10) .map(_._1) printStudentInfoWithId(ids) // 學號,姓名,班級,科目,分數(shù) } /** * 統(tǒng)計總分大于年級平均分的學生 [學號,姓名,班級,總分] */ private def xuQiu4(): Unit = { //先計算年級平均分 372 val avgScore: Int = scoreList.map(_.score).sum / stuList.size // println(avgScore) //計算每個人總分進行過濾 scoreList.groupBy((s: Score) => s.id) // 按照學號進行分組 .map((kv: (String, List[Score])) => { (kv._1, kv._2.map(_.score).sum) // 求每個學生的總分 }) .filter(_._2 > avgScore) .map((t: (String, Int)) => { //根據(jù)stuInfoMap獲取學生的姓名和班級 val nameWithClazz: String = stuInfoMap.getOrElse(t._1, "查無此人") s"[${t._1},$nameWithClazz,${t._2}]" }).foreach(println) } /** * 統(tǒng)計每科都及格的學生 [學號,姓名,班級,科目,分數(shù)] */ private def xuQiu5(): Unit = { //1500100001,1000001,98 val ids: List[String] = scoreList.filter((sco: Score) => sco.score >= subScoreMap.getOrElse(sco.subject_id, 0) * 0.6) .groupBy(_.id) // 根據(jù)學號分組,過濾6門考試都及格的學生 .filter(_._2.size == 6) .keys .toList printStudentInfoWithId(ids) } /** * 統(tǒng)計每個班級的前三名 [學號,姓名,班級,分數(shù)] */ private def xuQiu6(): Unit = { val ids: List[String] = scoreList .groupBy((s: Score) => s.id) // 按照學號進行分組 .map((kv: (String, List[Score])) => { val nameWithClazz: String = stuInfoMap.getOrElse(kv._1, "查無此人") val infos: Array[String] = nameWithClazz.split(",") val name: String = infos(0) val clazz: String = infos(1) (kv._1, name, clazz, kv._2.map(_.score).sum) // 求每個學生的總分 }) .groupBy(_._3) // 根據(jù)班級進行分組 .flatMap((kv: (String, Iterable[(String, String, String, Int)])) => { kv._2.toList.sortBy(-_._4).take(3) }).map(_._1).toList // 從總的學生成績信息中過濾出來 scoreList.filter((sco: Score) => ids.contains(sco.id)) .map { case Score(id: String, subject_id: String, score: Int) => { //根據(jù)學號,查找姓名和班級 stuInfoMap val nameWithClazz: String = stuInfoMap.getOrElse(id, "查無此人") s"[$id,$nameWithClazz,$score]" } }.foreach(println) } /** * 統(tǒng)計偏科最嚴重的前100名學生 [學號,姓名,班級,科目,分數(shù)] * * 方差 * (每個人的各科分數(shù)-6門考試的平均分)^2 / 科目數(shù) * */ private def xuQiu7(): Unit = { //歸一化 val ids: List[String] = scoreList.map { case Score(id: String, subject_id: String, score: Int) => (id: String, subject_id: String, score * 100 / subScoreMap.getOrElse(subject_id, 0)) }.groupBy(_._1) //根據(jù)學號進行分組 .map((kv: (String, List[(String, String, Int)])) => { val id: String = kv._1 val scoreList: List[(String, String, Int)] = kv._2 //每個人的平均分 val avgScore: Int = scoreList.map(_._3).sum / scoreList.size //求方差 val fangCha: Double = scoreList.map((t3: (String, String, Int)) => Math.pow(t3._3 - avgScore, 2)).sum / scoreList.size (id, fangCha) }) .toList .sortBy(-_._2) .take(100) .map(_._1) printStudentInfoWithId(ids) } def main(args: Array[String]): Unit = { loadData() // xuQiu1() // xuQiu2() // xuQiu3() // xuQiu4() // xuQiu5() // xuQiu6() xuQiu7() } //定義一個隱式轉換類 //將來可以直接通過文件路徑獲取一個封裝了行數(shù)據(jù)的集合 implicit class Load(path: String) { def load(): List[Array[String]] = { Source.fromFile(path).getLines().toList.map((line: String) => line.split(",")) } } } 柚子快報激活碼778899分享:開發(fā)語言 Scala學習 文章來源
本文內容根據(jù)網絡資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉載請注明,如有侵權,聯(lián)系刪除。