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