元組 元組是一個輕量級集合,這個集合可以存儲任意元素 元組是使用小括弧,元素之間使用逗號分隔,元素的類型是任意的 若需要訪問元組中的元素 [元組名._數字] 數字是從1開始, 有多少個元素,這個1遞增多少次 例如: 有一個元組,元組中有三個元素 訪問每一個元素值 --> _1 _2 _3 元組屬於輕 ...
元組是一個輕量級集合,這個集合可以存儲任意元素
元組是使用小括弧,元素之間使用逗號分隔,元素的類型是任意的
若需要訪問元組中的元素 [元組名._數字] 數字是從1開始, 有多少個元素,這個1遞增多少次
例如: 有一個元組,元組中有三個元素
訪問每一個元素值 --> _1 _2 _3
元組屬於輕量級的集合,數據最多只能存儲22個
ps:一般元組會代替Map在Spark中使用
對偶元組 --> 元組中存儲的數據是成對出現的,就將出現第一個值稱為key,第二個值的位置稱為Value
/** * 元組 */ object TupleDemo { def main(args: Array[String]): Unit = { //這個就是元組的創建 val t = ("sparkcore","sparkSQL","SparkStreaming") //獲取值 val value: String = t._1 //創建元組的同時,指定變數存儲數據(不推薦) val t1,(a,b,c) = ("sparkcore","sparkSQL","SparkStreaming") // val t1_1 = a //Scala中提供通過tuple元組類來創建 //tuple1是無限大 //剩餘的tuple後面的數字代表了最多可以存儲多少個元素 //系統給定元組的最大值是22個,超過22就無法存儲了,此時建議改為Array或List val tuple = new Tuple1(1.3,14,"你好") val tuple2 = new Tuple2(1.3,14) }
val tuple = new Tuple1(1.3,14,"你好") val tuple2 = new Tuple2(1.3,14) //遍歷方式1(迭代器遍歷) for(ele <- tuple.productIterator){ println(ele) } //遍歷集合 --> foreach 這個方法就是遍歷集合使用,沒有返回值 //foreach方法是獲取集合每一個元素並處理, 返回值是一個泛型,所以最終輸出什麼數據類型由需求決定 /* 方法: def 方法名(參數列表):返回值類型 = { 方法體 } 函數: val 函數名 = (參數列表) => {函數體} */ //先定義一個函數 val pt = (x:Any) =>{println(x)} tuple.productIterator.foreach(pt) //匿名函數 tuple.productIterator.foreach((x:Any) =>{println(x)}) //簡化 tuple.productIterator.foreach(x =>println(x)) //只需要一個可以獲取數據的變數--> 此時可以使用 下劃線代替 tuple.productIterator.foreach(println(_)) //因為是列印數據,此時參數是預設(就是遍歷集合獲取來的,此時Scala允許再次省略下劃線) tuple.productIterator.foreach(println)
拉鏈操作
package Scala_03 /** * 拉鏈操作 */ object TupleDemo2 { def main(args: Array[String]): Unit = { //zip就是元組的拉鏈操作,將兩個元組中數據進行合併,形成對偶元組 val name = Array("tom","jerry","kitty") val scores = Array(2,3,4) //當前數組中存儲的是一個一個的元組對象 //誰調用方法就是就是key,誰做參數傳遞 誰就是 value val tuples: Array[(String, Int)] = name.zip(scores) println(tuples.toBuffer) //兩個存儲數據的集合 中的數據不一致 val name_1 = Array("tom","jerry","kitty") val scores_2 = Array(2,3) //ps:如果兩個集合數據長度不一致,此時拉鏈操作誰以最小長度的集合為基準 進行對偶元組合併,多餘的部分會刪除 val tuples_2: Array[(String, Int)] = name_1.zip(scores_2) println(tuples_2.toBuffer) //zipAll 和zip是類似的,但是若齊總某一個集合集合中的元素缺少,將使用預設元素填充 val xs = List(1,2,3) val zx = List("一","二","三","四") val tuples_3 = xs.zipAll(zx,0,'_') println(tuples_3) //zipwithIndex 將集合中元素和所以進行結合 val list = List(1,2,3) val tuples_4 = list.zipWithIndex println(tuples_4.toBuffer) //若需要從指定位置開始組合 val tuples_5 = list.zip(Stream from 1) } }
列表List
Scala中的集合是分為可變和不可變
package Scala_03 /** * list集合 */ object ListDemo { def main(args: Array[String]): Unit = { val empty = List() //空集合 val names = List("xiaobai","xiaohong","xiaohuang") //有值 val moreList = List(List(1,2,3),List(2,3,4))// 集合中存儲的數據是另外一個集合對象 //運算符 //列表中有一個預設空值 nil 它可以和 :: 中綴符 一起使用 構建集合對象 // :: 和 nil一起使用 它 是右結合 val str:List[String] = ("小明" :: ("小紅" :: ("小黃" :: Nil))) println(str) val s = List("姓名") //將其他集合中數據添加到當前集合彙總 val strs :List[String] = "小明" :: "小紅" :: "小黃" :: s println(strs) //使用nil之後會將當前集合先看做是一個整體 nil就相當於創建了集合,所以當前所有數據 都會當前集合中元素進行存儲 // s 就會當做一個List集合對象存儲到當前集合中 val ss = "小明" :: "小紅" :: "小黃" :: s :: Nil println(ss) } }
package Scala_03 object ListDemo2 { def main(args: Array[String]): Unit = { val list = List(1,2,3) //所有不可變list操作都會返回一個全新的List val list2 = 0 :: list // 添加數據 val list3 = 0 +: list //都是向集合的開頭添加數據 val list4 = list :+ 4 //向集合的末尾提N家數據 val list5 = list ++ list4 //將兩個集合合併 //將某一個集合添加到當前集合的前面 val list6 = list4 ++: list val list6_1 = list4 ::: list //此操作和上面的操作是一樣的 } }
package Scala_03 object ListDemo3 { def main(args: Array[String]): Unit = { //遍歷集合的方法: /* 1.map遍歷集合獲取集合中每一個元素,並將元素進行處理(自定函數函數),返回一個全新的集合 2.filter遍歷集合獲取集合每一個元素,並將元素進行處理(這個自定義函數返回值必須是Boolean) 然後只有得到true,才會存儲到新的集合中 這兩個方法同樣適用於List */ //3.foreach 這個方法主要作用即使遍歷集合併處理集合中數據(自定義函數),這個方法沒有返回值 val list = List(1,2,3) val list_1: List[Int] = list.map(_*2) val list_2: List[Int] = list.filter(_>1) list.foreach((x:Int)=>println(x)) list.foreach(x => println(x)) list.foreach(println(_)) list.foreach(println) /* map和foreach的區別 1.map方法存在返回值,處理完數據之後會返回一個新的集合但是foreache是沒有返回值的,處理完數據之後時沒有返回結果的 2.因為map具有返回值,所以map多用於進行集合中數據處理,而foreach沒有返回值,所以多用於列印集合集合中數據 */ //ps:s雖然foreach不具備返回值,但是foreach內部處理函數和Map其實是一樣的,所以foreach也可以對集合中數據操作,操作完成之後多用於輸出 //例如 map將集合集合中的元素擴大二倍,foreach也可做到,但是不能返回值出新的集合 list.foreach(x=>println(x*2)) // list.max 最大值 list.min 最小值 //head 返回列表第一個元素 val head: Int = list.head //tail 返回除第一個元素之外的其他元素 val tail: List[Int] = list.tail //concat 將兩個集合拼接 相當於是 ++ val list1 = List(4,5,6) val newList: List[Int] = List.concat(list,list1) //反轉 val reverse: List[Int] = list.reverse //長度 //list.length list.size //take -> TopN 提取列表前N個數據 --> N就是具體的數值 val topN: List[Int] = list take 1 //拉鏈 zip zipAll zipwithIndex都可以使用 //list.sorted list.sortwith 都可以使用排序 //丟棄列表前N數據 --> N是具體的值 val ints: List[Int] = list drop 1 } }
package Scala_03 /* 可變ListBuffer */ object ListBufferDemo { def main(args: Array[String]): Unit = { import scala.collection.mutable.ListBuffer val list1 = ListBuffer[Int](1,2,3) val list2 = new ListBuffer[Int] list2 += 4 //追加 list2.append(1) list2 ++= list1 //添加集合 } } 對列表進行拆分 val list = List(1,2,3) val List(a,b,c) = list 此時 a b 和c 就會獲取 1,2,3的值
Set
package Scala_03 import scala.collection.immutable.HashSet import scala.collection.mutable /* 不可變和可變 HashSet是排重 Hash表 --> 數組+鏈表 */ object HashSetDemo { def main(args: Array[String]): Unit = { val set = new HashSet[Int]() val set1: HashSet[Int] = set+1 //添加 val set2 = set1 ++ Set(1,2,3)//合併集合 println(set2) //除了HashSet之外 可以使用使用Set val s = Set(1,2,3) import scala.collection.mutable._ val mutableSet = Set(1,2,3)//可變Set val set3 = new mutable.HashSet[Int]() set3 += 2 set3.add(4) //存在則刪除,不存在 不會報錯不生效 set3 -= 2 set3.remove(2) } }
package Scala_03 /** * 兩個Set集合操作 */ object SetDemo2 { def main(args: Array[String]): Unit = { //合併Set集合 val set1 = Set(5,6,9,20,30,45) val set2 = Set(50,60,9,20,35,55) val set = set1 ++ set2 //交集 println(set1.&(set2)) println(set1.intersect(set2)) //並集 println(set1.union(set2)) //差集 println(set1.diff(set2)) //遍歷Set val iterator = set1.iterator while(iterator.hasNext){ println(iterator.next) } } }
總結:
Scala中集合:分為可變和不可變
List Set Array Map -->可變和不可變,Array是定長和變長
元組輕量級存儲數據的一個集合,最多只能存儲22個元素多用於是對偶元組代替Map
在Spark中使用級別: 元組->Array-->List--->Map---->Set
集合常用方法
ps:方法主要是以Array和List為主,其餘Map和Set可以使用個別方法 遍歷集合: map 遍歷操作數據並返回 filter遍歷操作數據並返回 滿足Boolean表達式 foreach 遍歷操作數據但是沒有返回多用於列印 package Scala_03 /** * 常用方法 */ object CollectionMethodDemo { def main(args: Array[String]): Unit = { val list = List(List(1,2,3),List(4,5,6)) //要求: 將集合進行處理 並得到 一個 新的集合 List(1,2,3,4,5,6) //壓平集合(可以將集合中存儲的集合進行扁平化處理) //將集合存儲的集合對象進行扁平化處理(將存儲在集合對象中集合數據獲取出來形成一個新的集合) val flatten: List[Int] = list.flatten println(flatten) val line = List("hello tom hello jerry","hello xiaobai hello") //需求將當前集合中的數據進行處理 -- > List("hello","tom","hello".....) val stringses: List[Array[String]] = line.map(_.split(" ")) stringses.foreach(x=>println(x.toBuffer)) val list_1 = stringses.flatten println(list_1) //Scala中為了應對數據中存在集合套用集合的情況,推出 faltMap --> 就是flatten + Map 遍歷的同時並壓平 val line_1 = List("hello tom hello jerry","hello xiaobai hello") val strings: List[String] = line_1.flatMap(_.split(" ")) /* flatMap和Map的區別 都可以對數據繼續進行遍歷處理,.map只是對數據處理並不具備對數據的扁平化處理,flatmap是Flatten+Map結合體,即可以遍曆數據也可以對數據進行 扁平化處理,flatMap是Spark中比較常用獲取數據後的處理方法,其次是Map,但是flatMap是有局限性,在於它會壓平數據,不是所有的情況都需要壓平. */ //forall 對整個集合中元素進行條件過濾.只有當所有元素都滿足的時候,才會返回true 否則就是false val list_2 = List(1,2,3,4,5) val bool: Boolean = list_2.forall( _ < 3) //partition 分區 主要是對集合集合彙總數據進行分區(分組) //scala中體現就是出現不同集合, 但是在SparkCore中是存在不同分區中[Sparkcore中體現] val list_3 = List(1,2,3,4,5,6) //這boolean類型表達式決定如何分數據 val tuple: (List[Int], List[Int]) = list_3.partition(_%2 == 0) //fold 和 reduce //fold是一個聚合函數(求和) 需要兩個參數 第一個是預設值 第二個參數是計算邏輯 //計算流程: 首先x會先獲取0這個初始值,然後y會獲取集合第一個元素然後相加 // 之後的每一次計算 x獲取的都是上一次計算的結果 即 x = x+y // y值依舊獲取集合中剩餘的元素進行計算 ,最終停止是是y不能再獲取到集合元素時停止 val list_4 = List(1,2,3,4,5) val sum = list_4.fold(0)((x,y) => x+y) //reduce //計算流程 首先x和y會獲取集合中第一個或第二個元素的值併進行計算 --> 1+2 = 3 // 之後的每一次計算x獲取的是上一次計算的結果即 x = x+y 而y繼續獲取剩餘的集合中的元素參與運算 直到集合中沒有元素停止 list_4.reduce((x,y)=>x+y) } } 求和 sum 排序 sorted , sortwith 最大值 max 和 最小值 min
package Scala_03 /* Scala版本 模仿做的 */ object WordCount { def main(args: Array[String]): Unit = { // 讀取文件數據存儲在集合中 val line = List("hello tom hello jerry","hello xiaobai hello","hello tom") //將集合中的數據進行處理,,獲取集合中每一條字元串,將字元串進行拆分得到單詞 val words: List[String] = line.flatMap(_.split(" ")) //需要將單詞以KV的形式記性拼接 --> (單詞,1) --> 明確當前存儲類型就是kv鍵值對 // Scala中提供兩種方式 Map 和 元組 --> 推薦使用元組,原因在於元組擦操作數據更加方便,不會像Map一樣需要調用get方法獲取數據 val tuples: List[(String, Int)] = words.map((_,1)) //單詞和次數已經成為了元組,需要對次數進行累加,問題是不知道哪些單詞是一組 // 將相同的單詞進行分組 // key 單詞 value 原有單詞所存在的元組 val grouped: Map[String, List[(String, Int)]] = tuples.groupBy(_._1) //此時已經根據單詞進行了分組 相同的單詞會匯聚成List集合,通過reduce來進行計算可以相對來說比較麻煩 val sumed:Map[String,Int] = grouped.mapValues(_.size) //Top1 ,數據已經存在Map集合中,此時進行排序 val list: List[(String, Int)] = sumed.toList //Map轉換為List時會將kv鍵值對以元組的形式存 //這個排序是根據傳入的指定值來進行排序的,預設是升序,無法直接降序,Spark中有一個和這個方法一樣的sortBy,是可以自由升序降序 val sortedList = list.sortBy(_._2) val reverseList = sortedList.reverse val top1 = reverseList take 1 println(top1) //正常版本 val top2 = line.flatMap(_.split(" ")).map((_,1)).groupBy(_._1).mapValues(_.size).toList.sortBy(_._2).reverse.take(1) } }
原因:Spark是一個並行計算框架,基於記憶體,所以會開啟多個線程執行程式 Scala中可以使用par進行多線程模擬 package Scala_03 /** * 並行化 */ object ParDemo { def main(args: Array[String]): Unit = { /* Spark在編寫程式的時候,可以提交集群運行,也可以在本地執行 可以在編寫Spark程式的時候 進行本地運行配置setMaster 運行模式設置 需要開啟本地運行--> 我們三種方式 local --> 單線程 local[值] --> 更值來開啟對應的線程數,用來模擬spark的平行計算 local[*] --> * 主要代表當前電腦空閑多少線程就使用多少線程來進行模擬計算 */ //用par模擬並行化計算 //1.求和 -->聚合函數 --> sum , fold ,reduce //1.1 sum進行計算 println("--------------------------------sum計算------------------------------------") //ps:sum只能用來求和無法計算其他方式 val arr = List(1,2,3,4,5,6,7,8,9,10) //55 //單線程計算 val sumed = arr.sum println("單線程sum:"+sumed) // 1+2+3+4... //開啟平行化處理計算 val sumed2 = arr.par.sum println("多線程sum:"+sumed) //(1+2)+(3+4+5+6)+(7+8+9+10) //總結:無論是在單線程還是多線程計算求和計算結果都是沒有問題 println("--------------------------------sum計算------------------------------------") //reduce 求和 println("--------------------------------reduce計算------------------------------------") //ps:sum只能用來求和無法計算其他方式 val arr_1= List(1,2,3,4,5,6,7,8,9,10) //55 //單線程計算 val sumed3 = arr_1.reduce(_+_) println("單線程reduce:"+sumed3) // 1+2+3+4... //開啟平行化處理計算 val sumed3_1 = arr_1.par.reduce(_+_) println("多線程reduce:"+sumed3_1) //(1+2)+(3+4+5+6)+(7+8+9+10) //總結:無論是在單線程還是多線程計算求和計算結果都是沒有問題 //reduce是可以寫自己的計算邏輯,既然可以使用+ 同理也可以計算 - //單線程計算 val sub = arr_1.reduce(_-_) // 1-2-3-4... println("單線程reduce:"+sub) //開啟平行化處理計算 此時不知道有多少個線程線上程在執行(1-2) -(3-4-5) - (9-10) val sub_1 = arr_1.par.reduce(_-_) println("多線程reduce:"+sub_1) //在計算求差值計算時候reduce是無法保證在多線程下計算記過準確 // reduceleft 和 reduceright --> 無論是單線程還是多線程 ->都是按照一個方向計算計算的 //可以使用reduceleft來修正計算計算記過 --> 必須是從左向右計算 val sub_2 = arr_1.par.reduceLeft(_-_) println("多線程reduce:"+sub_2) //在Spark並行計算中如果需要使用計算求差值這樣的計算,建議使用 reduceLeft --> reduceRight計算邏輯和left是一樣的(從右向左) println("--------------------------------reduce計算------------------------------------") //fold 求和 println("--------------------------------fold計算------------------------------------") //ps:sum只能用來求和無法計算其他方式 val arr_2= List(1,2,3,4,5,6,7,8,9,10) //55 //單線程計算 val sumed4 = arr_2.fold(10)(_+_) println("單線程fold:"+sumed4) // 1+2+3+4... //開啟平行化處理計算 val sumed4_1 = arr_2.par.fold(10)(_+_) //fold一旦開啟並行化,就會進行多次的計算--> 當前整個初始值只要進行進行一次線程計算 //就會盡心一次10的相加 --> 例如: 10+1+2 --> 12 10+3+4 println("多線程fold:"+sumed4_1) //總結在平行化的前提下,fold 不建議進行 求和計算,因為會多次計算初始值,如果需要當前初始值只計算一次 //foldLeft 和 foldRight --> 強制要求計算方式是從左向後 和 從右向左 val sum5 = arr_2.par.foldLeft(10)(_+_) //聚合函數 aggregate 和 fold類似 但是 計數邏輯多 // aggregate(初始值)(局部聚合,全局聚合) --> aggregateByKey(SparkCore中運算元) println("--------------------------------fold計算------------------------------------") } }
|
|||||||||||||||
Scala中定義類和屬性
ps:在scala中描述一個事物需要使用class修飾的,在Scala中需要執行代碼即執行類需要使用object來修飾
Scala中 object代表的是類的修飾,而Java中Object代表的是超級父類,Scala中的超級父類是Any
package Scala_03 //Scala類中屬性 /* 在Scala中類並不需要使用public修飾,因為預設都是共有 在Scala中class修飾的類都是用來描述事物的,在沒有指定構造發方法之前,預設是存在一個無參構造方法的 */ class Student { //類中定義屬性 /* 因為Scala中對變數的修飾基本上即使var 和 val,這樣兩種修飾同樣適用於屬性 定義屬性時使用var修飾,那麼就相當於屬性自帶getter和setter 定義屬性時使用val修飾,那麼就相當於屬性自帶getter Scala類聲明屬性,如果使用自動推斷,必須顯示的進行賦值 不想使用自動推斷,此時必須明確表示該數據類型是什麼 */ var name = "tom" var age:Int = _ //當前屬性並不需要初始值,此時可以使用 _ 作為占位符代替初始值 //val修飾屬性不可以使用_ 占位因為是只讀屬性 只會被賦值一次,一但使用下劃線 就無法在賦新值 // val gender:String= _ //沒有明確數據類型,此時不允許使用下劃線 //var address = _ // 可以使用 私有修飾符 (伴生類可以訪問這個私有屬性) private var height :Int = 155 //對屬性更加嚴格的許可權控制 [this]代表只能當前類訪問 伴生類也不可以 private[this] val cardID = "123456" //創建對象 val student = new Student() // val student = Student//這樣的創建多用於是伴生類 --> 觸發 apply方法 Student必須是一個Object類 }
package Scala_03 /* 自定義getter和setter */ class Ponit { /* 為了保證數據安全,面向對象中封裝性 會將屬性進行私有化設置 做私有化屬性時建議的命名規則 要求以 _ 為首碼, 定義屬性的名字 例如 _屬性名 getter方法 def 方法名 = 當前屬性 --> 方法名是當前屬性的名字 setter方法 def 方法名(參數列表):Unit = { 對屬性賦值} --> 方法名必須是 屬性名_ */ private var _x = 0 //獲取這個屬性 getter def x = _x //賦值 setter def x_(x:Int):Unit = { _x = x } def showInfos()={ val p = new Ponit() //獲取屬性 println(p.x) p.x_(10) } }
Bean屬性
為了方便從Java程式猿轉變為Scala程式猿,方法理解和使用和Java中getter和Setter完全一樣
package Scala_03 import scala.beans.BeanProperty class Person { //在創建屬性時候提供getter和setter方法,使用是一個註解 @BeanProperty var name:String = _ } object Person{ def main(args: Array[String]): Unit = { val p = new Person() p.getName p.setName("1") } }
package Scala_03 import java.util import scala.collection.mutable /** * 集合互相轉換 */ object ScalaToJava { def main(args: Array[String]): Unit = { import scala.collection.JavaConverters._ //將當前集合轉換為Java中的List val javaC: util.List[Int] = List(1,2,3,4).asJava //Java中集合轉換為Scala中集合 val scalaC: mutable.Buffer[Int] = javaC.asScala //萬能方法 toXXXX -> XX就是你要轉換的集合 scalaC.toList } }