元组是一个轻量级集合,这个集合可以存储任意元素
元组是使用小括号,元素之间使用逗号分隔,元素的类型是任意的
若需要访问元组中的元素 [元组名._数字] 数字是从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 } }