7.1 集合简介
1)说明
(1)Scala的集合有三大类:序列Seq、集Set、映射Map,所有的集合都扩展自Iterable特质。
(2)对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本,分别位于以下两个包
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
2)案例实操
(1)Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。
(2)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。
package com.yuange.scala.day04 import scala.collection.mutable.ListBuffer object TestListOne { def main(args: Array[String]): Unit = { //不可变List val testList: List[Int] = List(1,3,5,23,2) println(testList) //对不可变的List进行修改,在头部添加一个元素0 val testList2 = 0 +: testList println(testList2) //可变List val testList3: ListBuffer[Int] = ListBuffer(1,3,5,7,4) println(testList3) //对可变list进行修改,在头部添加一个元素0 val testList4 = 0 +: testList3 println(testList4) } }
7.1.1 不可变集合继承图
1)Set、Map是Java中也有的集合
2)Seq是Java没有的,我们发现List归属到Seq了,因此这里的List就和Java不是同一个概念了
3)我们前面的for循环有一个 1 to 3,就是IndexedSeq下的Vector
4)String也是属于IndexeSeq
5)我们发现经典的数据结构比如Queue和Stack被归属到LinerSeq
6)大家注意Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持排序
7)IndexSeq和LinearSeq的区别:
(1)IndexSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位
(2)LineaSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
7.1.2 可变集合继承图
7.2 数组
7.2.1 不可变数组
1)第一种方式定义数组(定长数组)
val arr1 = new Array[Int](10)
(1)new是关键字
(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any
(3)(10),表示数组的大小,确定后就不可以变化
2)案例实操
package com.yuange.scala.day04 object TestArray { def main(args: Array[String]): Unit = { //定义数组 val testArray = new Array[Int](4) println(testArray.length) //数组赋值 testArray(2) = 100 //修改某个元素的值 testArray.update(0,200) //采用方法的形式给数组赋值 //遍历数组 println(testArray.mkString(",")) //查看数组 for (i <- testArray){ //普通遍历 print(i + "\t") } println() //简化遍历 def ergodic(i: Int): Unit = { println(i) } // testArray.foreach(ergodic) // testArray.foreach((i)=>{println(i)}) //简化 // testArray.foreach(i=>println(i)) // testArray.foreach(println(_)) testArray.foreach(println) //增加元素:由于创建的是不可变数组,所以是在产生新数组 println("------------------------") println(testArray.mkString(",")) val ints = testArray :+ 5 println(ints.mkString(",")) } }
3)第二种方式定义数组
val arr1 = Array(1, 2)
(1)在定义数组时,直接赋值
(2)使用apply方法创建数组对象
4)案例实操
package com.yuange.scala.day04 object TestArrayTwo { def main(args: Array[String]): Unit = { var testArray = Array("zhansan","李四","王五") for (i <- testArray){ println(i) } } }
7.2.2 可变数组
1)定义变长数组
val arr01 = ArrayBuffer[Any](3, 2, 5)
(1)[Any]存放任意数据类型
(2)(3, 2, 5)初始化好的三个元素
(3)ArrayBuffer需要引入scala.collection.mutable.ArrayBuffer
2)案例实操
(1)ArrayBuffer是有序的集合
(2)增加元素使用的是append方法(),支持可变参数
package com.yuange.scala.day04 import scala.collection.mutable.ArrayBuffer object TestArrayBuffer { def main(args: Array[String]): Unit = { //创建并赋值可变数组 val testBuffer = ArrayBuffer[Any](1,2,3) //遍历数组 for (i <- testBuffer){ println(i) } println("length=" + testBuffer.length) println("hash=" + testBuffer.hashCode()) //增加元素 testBuffer.+=(4) //追加数据 println(testBuffer) testBuffer.append(5) //想数组末尾添加数据 println(testBuffer) testBuffer.insert(3,6,7) //在角标为3的位置插入6和7,即插入之后6的角标为3,7的角标为4,角标从0开始计算 println(testBuffer) println("hash=" + testBuffer.hashCode()) //hashCode不一致 //修改元素 testBuffer(0) = 100 //修改第一个元素的值 println("*"*100) for (i <- testBuffer){ println(i) } println("length=" + testBuffer.length) } }
7.2.3 不可变数组与可变数组的转换
1)说明
arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
(1)arr2.toArray返回结果才是一个不可变数组,arr2本身没有变化
(2)arr1.toBuffer返回结果才是一个可变数组,arr1本身没有变化
2)案例实操
package com.yuange.scala.day04 import scala.collection.mutable.ArrayBuffer object TestArrayBufferTwo { def main(args: Array[String]): Unit = { //创建一个空的可变数组 val testBuffer = ArrayBuffer[Int]() //追加值 testBuffer.append(1,2,3) println(testBuffer) //转不可变数组 val newArray = testBuffer.toArray //返回的结果是一个新的定长数组集合且原数组集合没有变化 println("不可变数组=" + newArray) //转可变数组 val newBuffer = newArray.toBuffer //返回一个变长数组且原数组无任何变化,依然是定长数组 newBuffer.append(100) println(newBuffer) } }
7.2.4 多维数组
1)多维数组定义(二维数组中有三个一维数组,每个一维数组中有四个元素)
val arr = Array.ofDim[Double](3,4)
2)案例实操
package com.yuange.scala.day04 object DimArray { def main(args: Array[String]): Unit = { //创建一个二维数组,有三个元素,这三个元素中的每个元素含有四个元素 var testDim = Array.ofDim[Int](3,4) testDim(1)(2) = 100 //给第二行的第三列元素进行修改,数组脚标从0开始 //遍历二维数组 for (i <- testDim){ for (j <- i){ print(j + "\t") } println() } } }
7.3 Seq集合(List)
7.3.1 不可变List
1)说明
(1)List默认为不可变集合
(2)创建一个List(数据有顺序,可重复)
(3)遍历List
(4)List增加数据
(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
(6)取指定数据
(7)空集合Nil
2)案例实操
package com.yuange.scala.day04 object TestList { def main(args: Array[String]): Unit = { //List默认是不可变集合,创建一个List(数据有序,可重复) val testList: List[Int] = List(1,2,3,4,5) println("testList=" + testList) //空集合Nil val testList2 = 1 :: 2 :: 3 :: 4 :: 5 :: Nil println("testList2=" + testList2) //增加数据 val testList3 = 6 :: testList //::的运算规则是从右到左 println("testList3=" + testList3) val testList4 = 7 :: 8 :: 9 :: testList3 //将7,8,9插入到集合前面 println("testList4=" + testList4) val testList5 = testList4.+:(10) //将10插入到集合的第0位置 println("testList5=" + testList5) //集合间合并,将一个整体拆分为一个个体,扁平化 val testList6 = List(11,12) println("testList6=" + testList6) val testList7 = testList6 :: testList //::将testList6整个集合当成一个整体插入到testList集合前面 println("testList7=" + testList7) val testList8 = testList6 ::: testList println("testList8=" + testList8) //:::将testList6集合拆分成一个个个体然后插入到testList集合前面 //取指定数据 println("testList(3)=" + testList(3)) //遍历List集合 testList8.foreach(println) } }
7.3.2 可变ListBuffer
1)说明
(1)创建一个可变集合ListBuffer
(2)向集合中添加数据
(3)打印集合数据
2)案例实操
package com.yuange.scala.day04 import scala.collection.mutable.ListBuffer object TestListTwo { def main(args: Array[String]): Unit = { //创建可变集合 val testBuffer = ListBuffer(1,2,3,4,5) //向集合中添加数据 testBuffer.+=(6) //添加数据在集合后面 testBuffer.+=:(7) //添加数据在集合前面 //打印 testBuffer.foreach(println) } }
7.4 Set集合
默认情况下,Scala使用的是不可变集合,如果你想使用可变集合,需要引用 scala.collection.mutable.Set 包
7.4.1 不可变Set
1)说明
(1)Set默认是不可变集合,数据无序
(2)数据不可重复
(3)遍历集合
2)案例实操
package com.yuange.scala.day04 object TestSet { def main(args: Array[String]): Unit = { //set默认是不可变集合,数据无序 val testSet = Set(1,3,5,7,9) println("testSet=" + testSet) //数据不可重复 val testSet2 = Set(1,1,2,4,5,9); println("testSet2=" + testSet2) } }
7.4.2 可变mutable.Set
1)说明
(1)创建可变集合mutable.Set
(2)打印集合
(3)集合添加元素
(4)向集合中添加元素,返回一个新的Set
(5)删除数据
2)案例实操
package com.yuange.scala.day04 import scala.collection.mutable object TestSetTwo { def main(args: Array[String]): Unit = { //创建可变集合 val testSet = mutable.Set(1,2,3,4) println("testSet=" + testSet) //向集合中添加元素 testSet += 5 println("testSet=" + testSet) //向集合中添加元素,返回一个新的set val testSet2 = testSet.+(6) println("testSet2=" + testSet2) //删除数据 testSet2 -= 5 //遍历集合 testSet2.foreach(println) //打印集合并按,分割 println(testSet2.mkString(",")) } }
7.5 Map集合
Scala中的Map和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的。
7.5.1 不可变Map
1)说明
(1)创建不可变集合Map
(2)循环打印
(3)访问数据
(4)如果key不存在,返回0
2)案例实操
package com.yuange.scala.day04 object TestMap { def main(args: Array[String]): Unit = { //创建不可变集合Map val testMap = Map("zhangsan"->1001,"lisi"->1002,"wangwu"->1003) //访问数据 for (elem <- testMap.keys){ //使用get访问map集合中的数据,会返回特殊类型Option(选项):有值(Some),无值(None) println(elem + "=" + testMap.get(elem).get) } //若key不存在,返回0 println(testMap.get("zhaoliu").getOrElse(0)) println(testMap.getOrElse("zhaoliu",0)) //循环打印 testMap.foreach((kv)=>{println(kv)}) testMap.foreach(kv=>{println(kv)}) } }
7.5.2 可变Map
1)说明
(1)创建可变集合
(2)打印集合
(3)向集合增加数据
(4)删除数据
(5)修改数据
2)案例实操
package com.yuange.scala.day04 import scala.collection.mutable object TestMapTwo { def main(args: Array[String]): Unit = { //创建可变集合 val testMap = mutable.Map("zhangsan"->2001,"lisi"->2002,"wangwu"->2003) //向集合增加数据 testMap.+=("zhaoliu"->2004) println("testMap=" + testMap) //将数值2005添加到集合,并把集合中原值2001返回 val maybeInt: Option[Int] = testMap.put("zhangsan",2005) println(maybeInt.getOrElse(0)) //删除数据 testMap.-=("wangwu","lisi") println("删除数据之后:" + testMap) //修改数据 testMap.update("zhaoliu",2006) println("修改数据之后:" + testMap) //打印集合 testMap.foreach(kv=>{println(kv)}) } }
7.6 元组
1)元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组(元组中最大只能有22个元素)
2)案例实操
(1)声明元组的方式:(元素,元素2,元素3)
(2)访问元组
(3)Map中的键值对其实就是元组,只不过元组的元素个数为2,称之为对偶
package com.yuange.scala.day04 object TestTuple { def main(args: Array[String]): Unit = { //声明元组的方式:(元素1,元素2,元素3,...) val testTuple: (Int,String,Boolean) = (1001,"张三",true) //通过元素的顺序访问元组,调用方式:元组名称._顺序号 println("testTuple._1=" + testTuple._1 + ",testTuple._2=" + testTuple._2 + ",testTuple._3=" + testTuple._3) //通过索引访问数据 println("testTuple.productElement(0)=" + testTuple.productElement(0)) //通过迭代器访问数据 for (elem <- testTuple.productIterator){ println(elem) } //Map中的键值对就是元组,只不过元素的个数为2,称之为对偶 val testMap = Map("张三"->3001,"李四"->3002,"王五"->3003) testMap.foreach(kv=>{println(kv._1 + "=" + kv._2)}) } }
7.7 集合常用函数
7.7.1 基本属性和常用操作
1)说明
(1)获取集合长度
(2)获取集合大小
(3)循环遍历
(4)迭代器
(5)生成字符串
(6)是否包含
2)案例实操
package com.yuange.scala.day04 object Aggregate { def main(args: Array[String]): Unit = { val testList: List[Int] = List(1,3,5,7,9,11,13) //获取集合长度 println("testList.length=" + testList.length) //获取集合大小 println("testList.size=" + testList.size) //循环遍历 testList.foreach(println) //迭代器 for (i <- testList){ println(i) } //生成字符串 println(testList.mkString(",")) //是否包含 println(testList.contains(5)) } }
7.7.2 衍生集合
1)说明
(1)获取集合的头head
(2)获取集合的尾(不是头就是尾)tail
(3)集合最后一个数据 last
(4)集合初始数据(不包含最后一个)
(5)反转
(6)取前(后)n个元素
(7)去掉前(后)n个元素
(8)并集
(9)交集
(10)差集
(11)拉链
(12)滑窗
2)案例实操
package com.yuange.scala.day04 object AggregateTwo { def main(args: Array[String]): Unit = { val testList: List[Int] = List(1,2,3,4,5,6,7) val testList2: List[Int] = List(4,5,6,7,8,9,10,11) //获取集合的头 println("testList.head=" + testList.head) //获取集合的尾 println("testList.tail=" + testList.tail) //集合最好一个数据 println("testList.last=" + testList.last) //集合初始数据(不包含最后一个) println("testList.init=" + testList.init) //反转 println("testList.reverse=" + testList.reverse) //取前n个元素 var n = 3 println(testList.take(n)) //取后n个元素 println(testList.takeRight(n)) //去掉前n个元素 println(testList.drop(n)) //去掉后n个元素 println(testList.dropRight(n)) //并集 println(testList.union(testList2)) //交集 println(testList.intersect(testList2)) //差集 println(testList.diff(testList2)) //拉链:若两个集合的元素个数不相等,则将同等数量的数据进行拉链,多余的数据省略不用 println(testList.zip(testList2)) //滑窗:从第五个位置位置开始取两个数 testList.sliding(2,5).foreach(println) } }
7.7.3 集合计算初级函数
1)说明
(1)求和
(2)求乘积
(3)最大值
(4)最小值
(5)排序
2)实操
package com.yuange.scala.day04 object AggregateThree { def main(args: Array[String]): Unit = { val testList: List[Int] = List(1,3,-5,-7,9,-11) //求和 println("testList.sum=" + testList.sum) //求乘积 println("testList.product=" + testList.product) //求最大值 println("testList.max=" + testList.max) //求最小值 println("testList.min=" + testList.min) //按元素大小排序:升序 println(testList.sortBy(x => x)) //按元素的绝对值大小排序 println(testList.sortBy(x => x.abs)) //按元素大小升序排序 println(testList.sortWith((x,y) => x < y)) //按元素大小降序排序 println(testList.sortWith((x,y) => x > y)) } }
7.7.4 集合计算高级函数
1)说明
(1)过滤
(2)转化/映射
(3)扁平化
(4)扁平化+映射 注:flatMap相当于先进行map操作,在进行flatten操作
(5)分组
(6)简化(规约)
(7)折叠
2)实操
package com.yuange.scala.day04 object AggregateFour { def main(args: Array[String]): Unit = { val testList: List[Int] = List(1,2,3,4,5,6,7,8,9) val nestedList: List[List[Int]] = List(List(1,2,3),List(4,5,6),List(7,8,9)) val wordList: List[String] = List("hello world","hello yuange","hello scala") //过滤 println(testList.filter(x => x % 2 == 0)) //转化/映射 println(testList.map(x => x + 1)) //扁平化 println("nestedList.flatten=" + nestedList.flatten) //扁平化+映射:flatMap相当于先进行map操作,再进行flatten操作 println("扁平化+映射=" + wordList.flatMap(x => x.split(" "))) //分组 println(testList.groupBy(x => x % 2)) } }
3)Reduce方法
Reduce简化(规约) :通过指定的逻辑将集合中的数据进行聚合,从而减少数据,最终获取结果。
package com.yuange.scala.day04 object TestReduce { def main(args: Array[String]): Unit = { val testList: List[Int] = List(1,2,3,4,5) //将数据两两结合,实现运算 val i: Int = testList.reduce((x,y) => x - y) println("i=" + i) //从源码的角度,reduce底层调用的其实就是reduceLeft // val i2: Int = testList.reduce((x,y) => x - y) //((5-4)+(3-2)+1) = 3 val i3 = testList.reduceRight((x,y) => x - y) println("i3=" + i3) } }
4)Fold方法
Fold折叠:化简的一种特殊情况。
(1)案例实操:fold基本使用
package com.yuange.scala.day04 object TestFold { def main(args: Array[String]): Unit = { val testList = List(1,2,3,4,5) //fold方法使用了函数柯里化,存在两个参数列表 //第一个参数列表为:零值(初始值) //第二个参数列表为: //fold底层其实是foldLeft val i = testList.foldLeft(1)((x,y) => x - y) println("i=" + i) val i2 = testList.foldRight(10)((x,y) => x -y) println("i2=" + i2) } }
(2)案例实操:两个集合合并
package com.yuange.scala.day04 import scala.collection.mutable object TestFoldTwo { def main(args: Array[String]): Unit = { val map = mutable.Map("zhangsan"->1001,"lisi"->1002,"wangwu"->1003) val map2 = mutable.Map("zhangsan"->1004,"lisi"->1005,"zhaoliu"->1006) val map3: mutable.Map[String,Int] = map2.foldLeft(map){ (map,kv) => { val k = kv._1 val v = kv._2 map(k) = map.getOrElse(k,0) + v map } } println(map3) } }
7.7.5 普通WordCount案例
1)需求
单词计数:将集合中出现的相同的单词,进行计数,取计数排名前三的结果
2)需求分析
3)案例实操
package com.yuange.scala object TestWordCount { def main(args: Array[String]): Unit = { //单词计数:将集合中出现的相同单词,进行计数,取计算排名前三的结果 val testList = List("Hello Scala Hbase kafka", "Hello Scala Hbase", "Hello Scala", "Hello") //将每个字符串按空格进行切分并将切分好的单词放入List集合 val str: List[String] = testList.flatMap(x => x.split(" ")) //将相同的单词放在一起(分组) val str2: Map[String,List[String]] = str.groupBy(x => x) //对相同的单词进行计算 val str3: Map[String,Int] = str2.map(x => (x._1,x._2.size)) //对结果进行降序排序 var sortList: List[(String,Int)] = str3.toList.sortWith{ (left,right) => { left._2 > right._2 } } //对排序后的结果取前三 val result: List[(String,Int)] = sortList.take(3) println(result) } }
7.7.6 复杂WordCount案例
1)方式一
2)案例实操
package com.yuange.scala.day04 object TestWordCounTwo { def main(args: Array[String]): Unit = { val testList = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1)) val testList2: List[String] = testList.map(x => (x._1 + " ")*x._2) println("testList2=" + testList2) val word: List[String] = testList2.flatMap(_.split(" ")) println("word=" + word) val groupMap: Map[String,List[String]] = word.groupBy(str => str) println("groupMap=" + groupMap) val number: Map[String,Int] = groupMap.map(i => (i._1,i._2.size)) println("number=" + number) val sortNumber: List[(String,Int)] = number.toList.sortWith{ (left,right) => { left._2 > right._2 } }.take(3) println("sortNumber=" + sortNumber) } }
3)方式二
4)案例实操
package com.yuange.scala.day04 object TestWordCounThree { def main(args: Array[String]): Unit = { val tuples = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1)) val testList: List[(String,Int)] = tuples.flatMap{ t => { val str: Array[String] = t._1.split(" ") str.map(word => (word,t._2)) } } val testMap: Map[String,List[(String,Int)]] = testList.groupBy(t=>t._1) val testMap2: Map[String,List[Int]] = testMap.mapValues{ datas => datas.map(t => t._2) } val testMap3: Map[String,Int] = testMap2.map(t => (t._1,t._2.sum)) println(testMap3) } }
7.8 队列
1)scala也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为enqueue和dequeue。
2)案例实操
package com.yuange.scala.day04 import scala.collection.mutable object TestQueue { def main(args: Array[String]): Unit = { val que = new mutable.Queue[String]() que.enqueue("zhangsan","lisi","wangwu") println(que.dequeue()) println(que.dequeue()) println(que.dequeue()) } }
7.9 并行集合
1)Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
2)案例实操
package com.yuange.scala.day04 object TestPar { def main(args: Array[String]): Unit = { val result = (0 to 100).map{case_ => Thread.currentThread.getName} val result2 = (0 to 100).map{case_ => Thread.currentThread.getName} println(result) println(result2) } }