一、集合类型
集合是⼀种用来存储各种对象和数据的容器。Scala 集合分为可变的和不可变的集合。
1. 不可变集合可以安全的并发访问。
2. 可变集合可以在适当的地⽅被更新或扩展。这意味着你可以修改,添加,移除⼀个集合的元素。
Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质,意味着 集合的基本特点是⽀持迭代遍历的。
scala集合两个主要的包:
# 不可变集合
scala.collection.immutable (Scala默认采用不可变集合)
# 可变集合
scala.collection.mutable
分类 | 描述 |
Seq | 序列。元素以线性方式存储,集合中可以存放重复对象。 |
Set | 集(数据集,区别于集合)。集中的对象不按特定的方式排序,并且没有重复对象。 |
Map | ⼀种把键对象和值对象映射的集合,它的每⼀个元素都包含⼀对键对象和值对象。 |
对于可变与不可变集合,Seq、Set、Map又有不同的实现方式,下面两张图详细描述了其继承关系。
1.数组
任何数组都是可变集合
数组包括:Array(定长)和ArrayBuffer(变长)
# Array
- 定长数组,数组不可扩容 scala.Array
# ArrayBuffer
- 变长数组,数组可扩容 scala.collection.mutable.ArrayBuffer
val arr=Array(1,2,3)
val arr1=new Array(100)
scala> arr :+ 4 //+:
res306: Array[Int] = Array(1, 2, 3, 4)
arr是定长数组,不能修改长度,这里是返回新的数组,原数组并没有被修改
# 什么时候用new
如果没有提供object的apply方法时,class必须用new.
定长数组
arr是定长数组,不能改变长度
定⻓数组是不可变集合吗? 不是。定长数组是可变集合的⼀种,内容可变,但是其长度不可变。
# 扩展:为什么定长数组是可变集合?
Array本身不属于scala集合成员,从前⾯类继承图中也可发现这⼀点,在可变集合图中IndexedSeq有⼀条虚线指向了Array,说明并不是直接继承关系。
⼀般将Array归为集合是因为Scala默认将Array隐式转换为WrappedArray,⽽WrappedArray实现了IndexedSeq特质。
从这⼀点上来说,String与WrappedString也有异曲同⼯之妙,可以发现在不可变集合中,String与IndexedSeq也是虚线连接,也就是说在Scala中,String可以当集合处理。参考下⽂中的描述,请⾃⾏通过源码验证。
Array被隐式转换为WrappedArray(scala.collection.mutable.WrappedArray),间接拥有了集合的特征。
//Predef.scala 提示:所有scala⽂件默认导⼊Predef对象
implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] =
if (xs eq null) null
else WrappedArray.make(xs)
变长数组 ArrayBuffer
# ArrayBuffer的创建
1)直接创建
2)由Array转化
# 由arr转化 arr.toBuffer
scala> arr.toBuffer
res286: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
scala> arr.toBuffer+=4
res287: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3, 4)
scala> res286
res289: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3)
scala> res287
res290: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3, 4)
# 直接创建
scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
scala> val arrBuff=ArrayBuffer(1, 2, 3)
arrBuff: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)
小结:ArrayBuffer是在原来的Buffer上修改.
+: 返回新的对象
+= 是在原对象上修改
Array(1,2,3,4,5).filter(_%2==0).map(_*2).foreach(println)
2 元组
Scala Tuple表示固定元素的组合,元组可以装着多个不同类型的值,是不同类型的值的聚集。Tuple是Scala中⾮常 重要的⼀种数据结构,后⾯会大量使用。其特点包括:
- 最多⽀持22个元素组合,分别对应类型Tuple1~Tuple22,相应也称为⼀元组(⼀般不用)、⼆元组、三元组...
- 元组可以容纳不同类型的元素
- 元组不可变
创建元组:使用小括号 () 将多个元素括起来,元素之间⽤逗号分隔,元素的类型和个数不超过22。
访问组元:使用 _1 , _2 , _3 等形式访问组元,注意下标从1开始。
scala> val stu=(101,"oak","male",24)
stu: (Int, String, String, Int) = (101,oak,male,24)
scala> stu._1
res0: Int = 101
scala> stu._2
res1: String = oak
注意和同时定义多个变量的区别
scala> val (x,y,m,n)=(100,"jason","man",100)
x: Int = 100
y: String = jason
m: String = man
n: Int = 100
元组不能修改
scala> stu._3="xx"
<console>:15: error: reassignment to val
stu._3="xx"
因为元组不是集合,所以不能直接遍历,需要间接转换为集合进行遍历。
scala> for(i<-stu)println(i)
<console>:17: error: value foreach is not a member of (Int, String, String, Int)
for(i<-stu)println(i)
^
scala> for(i<-stu.productIterator)println(i)
100
jason
man
100
Traversable(可以重复遍历) & TraversableOnce(只能遍历一次) 的区别
元组对应的类型为 Tuple1-Tuple22
为什么没有Tuple0? ()
特别地:Tuple2 常用于表示对偶,可以表示Map中的⼀个元素,Map是K/V对偶的集合,对偶是元组的最简单形式。
scala> (1,("jason","man"))
res349: (Int, (String, String)) = (1,(jason,man))
scala> (1,Array("jason","man"))
res350: (Int, Array[String]) = (1,Array(jason, man))
scala> val tp2=Tuple2(1,2)
tp2: (Int, Int) = (1,2)
scala> val tp2="a"->100
tp2: (String, Int) = (a,100)
样例类的创建
scala> case class student(id: Int,name: String)
defined class student
拉链操作:
元组需要转换为集合进行拉链操作
scala> val tp3=(1,2,3)
tp3: (Int, Int, Int) = (1,2,3)
scala> val tp3_1=(1,2,3)
tp3_1: (Int, Int, Int) = (1,2,3)
scala> tp3.productIterator.toList zip tp3_1.productIterator.toList
res364: List[(Any, Any)] = List((a,1), (b,2), (c,3))
scala> Array("a","b").zipAll(Array(1,2,3),"",0)
res367: Array[(String, Int)] = Array((a,1), (b,2), ("",3))
scala> Array("a","b","c").zipAll(Array(1,2),"",0)
res2: Array[(String, Int)] = Array((a,1), (b,2), (c,0))
scala> List(("a",1), ("b",2), ("c",0)).unzip
res5: (List[String], List[Int]) = (List(a, b, c),List(1, 2, 0))
最常用的方法:
scala> Array("a","b").zipWithIndex
res6: Array[(String, Int)] = Array((a,0), (b,1))
scala> Array("a","b").zipWithIndex.foreach(x=>println(x.swap))
(0,a)
(1,b)
3 映射(Map)
3.1 不可变Map的创建
scala> val scores = Map("zhangsan"->70,"lisi"->80,"wangwu"->90)
scores: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 70, lisi -> 80, wangwu -> 90)
# 无法修改Map中的值
scala> scores("zhangsan")=91
<console>:16: error: value update is not a member of scala.collection.immutable.Map[String,Int]
scores("zhangsan")=91
scala> scores.keys
res384: Iterable[String] = Set(zhangsan, lisi, wangwu)
scala> scores.values
res385: Iterable[Int] = MapLike(90, 80, 70)
取值
scala> scores.get("zhangsan")
res390: Option[Int] = Some(90)
scala> scores.get("zhangsan").get
res391: Int = 90
# 推荐使用
scala> scores.getOrElse("zhangsan",0)
res392: Int = 90
移除n个元素
# 移除0个元素
scala> scores.drop(0)
res393: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 90, lisi -> 80, wangwu -> 70)
scala> scores.drop(1)
res394: scala.collection.immutable.Map[String,Int] = Map(lisi -> 80, wangwu -> 70)
scala> scores.drop(2)
res395: scala.collection.immutable.Map[String,Int] = Map(wangwu -> 70)
# 不可变map不发生变化
scala> scores
res396: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 90, lisi -> 80, wangwu -> 70)
添加元素
//map 没有+:操作,只有 +
scala> scores + ("d"->5)
res404: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 90, lisi -> 80, wangwu -> 70, d -> 5)
# 未发生变化
scala> scores
res405: scala.collection.immutable.Map[String,Int] = Map(zhangsan -> 90, lisi -> 80, wangwu -> 70)
遍历操作
# 注意以下两种方式的区别
scala> for(kv<-scores) println(kv)
(zhangsan,90)
(lisi,80)
(wangwu,70)
scala> for((k,v)<-scores) println(k,v)
(zhangsan,90)
(lisi,80)
(wangwu,70)
scala> for(kv<-scores) println(kv._1)
zhangsan
lisi
wangwu
scala> for(kv<-scores) println(kv._2)
90
80
70
scala> scores foreach println
(zhangsan,90)
(lisi,80)
(wangwu,70)
注意:map的默认实现就是HashMap
scala> val scores = scala.collection.immutable.HashMap("zhangsan"->90,"lisi"->80,"wangwu"->70,"zhaoliu"->66,"xx"->88)
scores: scala.collection.immutable.HashMap[String,Int] = Map(xx -> 88, lisi -> 80, zhaoliu -> 66, wangwu -> 70, zhangsan -> 90)
scala> val scores = scala.collection.immutable.TreeMap("zhangsan"->90,"lisi"->80,"wangwu"->70,"zhaoliu"->66,"xx"->88)
scores: scala.collection.immutable.TreeMap[String,Int] = Map(lisi -> 80, wangwu -> 70, xx -> 88, zhangsan -> 90, zhaoliu -> 66)
HashMap和TreeMap的转换
# 直接转换 无效
scala> scores.asInstanceOf[TreeMap[String,Int]]
java.lang.ClassCastException: scala.collection.mutable.HashMap cannot be cast to scala.collection.immutable.TreeMap
... 32 elided
# 先创建TreeMap 再遍历HashMap添加
scala> var tm=TreeMap[String,Int]()
scala> scores.foreach(kv=>tm=tm+(kv))
scala> tm
res439: scala.collection.immutable.TreeMap[String,Int] = Map(a -> 1, lisi -> 80, wangwu -> 70, xx -> 88, zhangsan -> 90, zhaoliu -> 66)
3.2 创建可变Map
== 可变Map使用较多 ==
scala> val scores = scala.collection.mutable.Map("zhangsan"->90,"lisi"->80,"wangwu"->70,"zhaoliu"->66,"xx"->88)
scores: scala.collection.mutable.Map[String,Int] = Map(lisi -> 80, zhangsan -> 90, zhaoliu -> 66, xx -> 88, wangwu -> 70)
scala> val scores = scala.collection.mutable.HashMap("zhangsan"->90,"lisi"->80,"wangwu"->70,"zhaoliu"->66,"xx"->88)
scores: scala.collection.mutable.HashMap[String,Int] = Map(lisi -> 80, zhangsan -> 90, zhaoliu -> 66, xx -> 88, wangwu -> 70)
scala> scores.get("lisi")
res441: Option[Int] = Some(80)
scala> scores("lisi")=91
scala> scores.get("lisi")
res443: Option[Int] = Some(91)
添加元素
//推荐使用
scala> scores.put("a",1)
res444: Option[Int] = None
scala> scores
res445: scala.collection.mutable.Map[String,Int] = Map(lisi -> 91, zhangsan -> 90, a -> 1, zhaoliu -> 66, xx -> 88, wangwu -> 70)
// + 返回的是新的map对象
scala> scores + ("b"->2)
res446: scala.collection.mutable.Map[String,Int] = Map(b -> 2, lisi -> 91, zhangsan -> 90, a -> 1, zhaoliu -> 66, xx -> 88, wangwu -> 70)
# 原来的Map未发生改变
scala> scores
res447: scala.collection.mutable.Map[String,Int] = Map(lisi -> 91, zhangsan -> 90, a -> 1, zhaoliu -> 66, xx -> 88, wangwu -> 70)
4 列表(List)
4.1 List 不可变
scala> List(1,2,3)
res451: List[Int] = List(1, 2, 3)
scala> (1 to 100) toList
warning: there was one feature warning; re-run with -feature for details
res452: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100)
# 数组
scala> Array(1,2,3).toList
res453: List[Int] = List(1, 2, 3)
# 元组
scala> (1,2,3).productIterator.toList
res455: List[Any] = List(1, 2, 3)
scala> Map("a"->1).toList
res456: List[(String, Int)] = List((a,1))
scala> Seq(1,2,3)
res457: Seq[Int] = List(1, 2, 3)
scala> 9 :: 5 :: 2 :: Nil
res464: List[Int] = List(9, 5, 2)
scala> List(1):::List(2)
res470: List[Int] = List(1, 2)
scala> val lst1=List(1)
lst1: List[Int] = List(1)
scala> lst1:+123
res473: List[Int] = List(1, 123)
scala> lst1
res474: List[Int] = List(1)
# 没有new List(100)这种写法 了解实际上List这样创建出来的
scala> List(1,2,3).getClass
res496: Class[_ <: List[Int]] = class scala.collection.immutable.$colon$colon
scala> $colon$colon(1,$colon$colon(2,$colon$colon(3,Nil)))
res500: scala.collection.immutable.::[Int] = List(1, 2, 3)
# new scala.collection.immutable.::(x, this)
4.2 ListBuffer 可变
scala> import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer
scala> val buf=ListBuffer(1,2,3)
buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
# :+ 返回新的对象
scala> buf:+4
res475: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4)
scala> buf
res476: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3)
# += 在原来的List上更改
scala> buf+=4
res478: buf.type = ListBuffer(1, 2, 3, 4)
scala> buf
res479: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4)
scala> buf++=ListBuffer(7,8)
res482: buf.type = ListBuffer(1, 2, 3, 4, 7, 8)
scala> buf
res483: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2, 3, 4, 7, 8)
5 Set
Set中的元素不可重复,无序(TreeSet除外)
5.1 创建不可变Set
scala> import scala.collection.immutable.HashSet
import scala.collection.immutable.HashSet
scala> val set0=Set(1,2,3,4,5)
set0: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
scala> println(set0.getClass)
class scala.collection.immutable.HashSet$HashTrieSet
# 默认的Set
scala> val set1 = new HashSet[Int]()
set1: scala.collection.immutable.HashSet[Int] = Set()
# 可以使⽤加号追加元素,会产⽣⼀个新的集合,原有set不变
scala> val set2 = set1 + 1
set2: scala.collection.immutable.HashSet[Int] = Set(1)
scala> set1
res3: scala.collection.immutable.HashSet[Int] = Set()
# Set集合中不会出现重复的元素
scala> val set3 = set2 ++ Set(1,2,3)
set3: scala.collection.immutable.HashSet[Int] = Set(1, 2, 3)
scala> val set4 = Set(1,2,3,4,5,6)
set4: scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)
# Set集合中的元素是⽆序的
scala> print(set4)
Set(5, 1, 6, 2, 3, 4)
# SortedSet中是有序的
scala> val set5=scala.collection.immutable.TreeSet(1,1,10,5,6,7,8,11,13)
set5: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 5, 6, 7, 8, 10, 11, 13)
5.2 创建可变Set
import scala.collection.mutable
object MutSetDemo extends App{
val mutableSet = Set(1,2,3)
println(mutableSet.getClass.getName) // scala.collection.mutable.HashSet
//创建⼀个可变的HashSet
val set1 = new mutable.HashSet[Int]()
//向HashSet中添加元素
set1 += 2
//add等价于+=
set1.add(4)
//删除⼀个元素,如果删除的对象不存在,则不⽣效,也不会报错
set1 -= 5
set1.remove(2)
println(set1)
}
5.3 集合的基本操作
Scala集合有三个基本操作:
- head 返回集合第⼀个元素
- tail 返回⼀个集合,包含除了第⼀元素之外的其他元素
- isEmpty 在集合为空时返回true
查找集合中最⼤与最⼩元素:
可以使⽤ Set.min ⽅法来查找集合中的最⼩元素,使⽤ Set.max ⽅法查找集合中 的最⼤元素。
5.4 两个set之间的常用操作
1)连接两个集合
使⽤ ++ 运算符或 Set.++() ⽅法来连接两个集合。如果元素有重复的就会移除重复的元素。
2)集合的交集
使⽤ Set.&()⽅法或 Set.intersect() 方法来查看两个集合的交集元素。
3)常用方法
- &:交集运算
- &~:差集运算
- union:并集运算
- contains:是否包含某⼀元素,包含返回true,不包含返回false
- count:计算满足指定条件的集合元素个数
- iterator:获得⼀个迭代器,可⽤于集合遍历
- size:返回集合元素的数量
- splitAt:将集合拆分为两个容器,第⼀个由前n个元素组成,第⼆个由剩下的元素组成
- take:返回前n个元素
- takeRight:返回后n个元素
- 使用to{type}转换为其他集合类型
二、集合的应用
1 集合的重要函数
/*
常⽤⽅法
基本上集合中都可以使⽤,极个别使⽤不上
Spark中常⽤的集合: Array List 元组 Map Set
*/
object CollectionMethodDemo {
def main(args: Array[String]): Unit = {
/*
map遍历集合处理集合中数据并返回⼀个全新集合
filter遍历集合提供⼀个函数指定过滤规则,对集合中数据继续过滤,满⾜需求的会被过滤出来形成⼀个新的集合
聚合函数(求和)sum 将集合中每⼀个元素相加求出最终和(具备可加性) --> 数值
max和min 最⼤值和最⼩值(了解)
foreach遍历集合主要是打印集合中数据(也可以操作集合中数据但是不能新的集合) --> 输出
sorted 排序 --> 升序 降序 可以考虑 reverse(翻转)
sortwith 需要传⼊⽐较参数,这个参数⽐较会决定是升序还是降序
第⼀个参数 > 第⼆个参数 降序
第⼀个参数 < 第⼆个参数 升序
ps:这些⽅法Array和List基本上都可以使⽤
Map和Set选择使⽤ 元组也是选择使⽤
*/
//1.Flatten 可以将存储在集合内部的集合压平
val list:List[List[Int]] = List(List(1,2,3),List(4,5,6),List(7,8,9))
//List(1,2,3,4,5,6,7,8,9)
val flatten: List[Int] = list.flatten
println(flatten)
//set集合中提供了特殊的操作 --交集,并集和差集
val num1 = Set(5,6,9,20,30,45)
val num2= Set(50,60,9,20,35,55)
//交集
println(num1.intersect(num2))
//并集
println(num1.union(num2))
//差集
println(num1.diff(num2))
//forall 对集合中的元素条件进⾏过滤,只有当所有元素都满⾜要求时,才会返回true 否则返回false
val list1 = List(1,2,3,4,5)
val bool:Boolean = list1.forall(_ < 3)
//Partition 分区
//ps:Scala中只能模拟,Spark中可以做到这个分区
//根据传⼊的函数 将数据吸⼊到不同存储位置中
val list2 = List(1,2,3,4,5,6)
//返回值类型是⼀个元组
val tuple: (List[Int], List[Int]) = list2.partition(_%2 ==0)
val list2_1 = tuple._1
//两个聚合函数
//1. fold 求和 ⽐较特殊需要两个参数 ⼀个是默认值,另外⼀个是计算逻辑
// 当前fold是典型的 柯⾥化
val list3 = List(1,2,3,4,5)
//计算
//[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
//现在属于是单线程,效果是看出来, 使⽤par的时候会出现多线程状态
val sum = list3.fold(2)((res,n)=>res+n)
println(sum)
//fold有两个变种 foldleft 和 foldright
//2.reduce 直接求和 通过计算逻辑 进⾏集合中数据的计算
val list4 = List(1,2,3,4,5)
val sum2 = list4.reduce((x,y)=>x+y)
//reduce也有两个变种 reduceleft 和 reduceright
}
}
2 并行集合
Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。 主要用到的算法有:
# Divide and conquer : 分治算法,Scala通过splitters,combiners等抽象层来实现,主要原理是将计算⼯作分解很多任务,分发给⼀些处理器去完成,并将它们处理结果合并返回
# Work stealin:工作窃取算法,主要⽤于任务调度负载均衡(load-balancing),通俗点完成⾃⼰的所有任务之后,发现其他⼈还有活没⼲完,主动(或被安排)帮他⼈⼀起⼲,这样达到尽早⼲完的⽬的。
1)打印1~5
scala> (1 to 5).foreach(println(_))
1
2
3
4
5
scala> println()
scala> (1 to 5).par.foreach(println(_))
3
1
4
2
5
2) 查看并行集合中元素访问的线程
scala> val result1 = (0 to 10000).map{case _ => Thread.currentThread.getName}.distinct
result1: scala.collection.immutable.IndexedSeq[String] = Vector(main)
scala> val result2 = (0 to 10000).par.map{case _ => Thread.currentThread.getName}.distinct
result2: scala.collection.parallel.immutable.ParSeq[String] = ParVector(ForkJoinPool-1-worker-25, ForkJoinPool-1-worker-23, ForkJoinPool-1-worker-29, ForkJoinPool-1-worker-13, ForkJoinPool-1-worker-31, ForkJoinPool-1-worker-21, ForkJoinPool-1-worker-11, ForkJoinPool-1-worker-15, ForkJoinPool-1-worker-3, ForkJoinPool-1-worker-19, ForkJoinPool-1-worker-1, ForkJoinPool-1-worker-5, ForkJoinPool-1-worker-17, ForkJoinPool-1-worker-9, ForkJoinPool-1-worker-7, ForkJoinPool-1-worker-27)
scala> println(result1)
Vector(main)
scala> println(result2)
ParVector(ForkJoinPool-1-worker-25, ForkJoinPool-1-worker-23, ForkJoinPool-1-worker-29, ForkJoinPool-1-worker-13, ForkJoinPool-1-worker-31, ForkJoinPool-1-worker-21, ForkJoinPool-1-worker-11, ForkJoinPool-1-worker-15, ForkJoinPool-1-worker-3, ForkJoinPool-1-worker-19, ForkJoinPool-1-worker-1, ForkJoinPool-1-worker-5, ForkJoinPool-1-worker-17, ForkJoinPool-1-worker-9, ForkJoinPool-1-worker-7, ForkJoinPool-1-worker-27)
3 WordCount
/**
* 单词统计
*/
object Scala_WordCount {
def main(args: Array[String]): Unit = {
//数据
val line = List("hello tom hello jerry","hello xiaobai hello","hello tom")
// 要求将数据进⾏处理得到的结果
//List("hello","tom","hello","jerry","hello","xiaobai","hello","hello","tom")
/*flatten+Map实现
val words: List[Array[String]] = line.map(_.split(" "))
val flatten: List[String] = words.flatten
println(flatten)
*/
//1.flatMap --> flatten+Map 具备在遍历处理数据同时,将数据将数据进⾏扁平化处理
//在处理数据的时候⼀定要返回⼀个集
val words:List[String] = line.flatMap(_.split(" "))
println(words)
// 可以仿照MR中Map阶段,对单词拼接形成kv键值对 单词,1
val tuples: List[(String, Int)] = words.map((_,1))
println(tuples)
//MR中kv键值对会发送到Reduce然后会出现相同key为⼀组计算⼀次reduce
//因为处理是单词,仿照MR中Reduce端处理逻辑,相同key在⼀起,Scala中提供groupBy根据传⼊参数进⾏分组
//返回值时⼀个Map
val grouped: Map[String, List[(String, Int)]] = tuples.groupBy(_._1)
println(grouped)
//Map的组成是 key 是单词 value是具体的单词对应元组 其中元组是使⽤List存储
//此时只需要知道key所对应value中List元素的个数,就可以知道当前单词的个数了
//mapValues是处理Map集合中value的值,只操作value,原则是对应key的value值,返回值是⼀个Map[key是原有的可以,value是计算结果之后的value]
val sumed: Map[String, Int] = grouped.mapValues(_.size)
println(sumed)
val list: List[(String, Int)] = sumed.toList
/**
* sortBy分为两种⼀种是Scala版本 另外⼀种是Spark版本
* Scala版本在没有使⽤隐式转换⾃定义的前提下,sortBy只能升序不能降序
* Spark版本中sortBy有两个参数 ⼀个是根据谁来排序, 第⼆个参数是Boolean类型 true是升序 false降序
*/
//参数是⼀个⽐较原则
val sorted: List[(String, Int)] = list.sortBy(_._2)
//topN 降序排序
val top1 = sorted take 1
println(sorted)
//简化版本
//line.flatMap(_.split(" ")).map((_,1))
// .groupBy(_._1).mapValues(_.size).toList.sortBy(_._2).take(1)
}
}
4 Java和Scala集合的互操作
# Scala中的集合和Java中集合互相转换 引⽤⼀个包即可
import scala.collection.JavaConverters._
# 将Scala集合转换为Java集合
val list:java.util.List[Int]=List(1,2,3,4,5).asJava
# 将Java集合转换为Scala
val buffer: mutable.Buffer[Int] = list.asScala
# toXXX 转换成需要的集合类型即可 --> XXX是集合名字 例如Array