scala集合
1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable 特质。
2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两 个包 不可变集合:scala.collection.immutable 可变集合: scala.collection.mutable
3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而 不会对原对象进行修改。类似于 java 中的 String 对象
4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似 于 java 中 StringBuilder 对象
下面是尚硅谷里的两张关于可变集合与不可变集合的继承图。
1.数组
1.1不可变数组
val ints = new Array[Int](10) //[T](size)
//[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
ints.update(0,2)//修改!
println(ints.apply(1)) // 和get()类似
val ints3 :Array[Int] = ints :+5 //加在数组后面
//直接生成字符串用,分割
println(ints.mkString(","))
//遍历有两种方式
for (elem <- ints) {
print(elem+" ") //Array的Index也是从0开始,且,数组Int的默认值是0
}
def printx(elem:Int):Unit= {
println(elem)
}
ints.foreach(printx)
1.2可变数组ArrayBuffer
val ab = ArrayBuffer[Int](1,2,3,1)
val aabb = new ArrayBuffer[Int]//()可加可不加
ab.sizeHint(10)//指定一个暗示大小,节约空间,超了,系统根据该Hint值扩大数组(增大,复制)
//ab.clear()
// ab.remove(0,2)//(index,count)连续去除count次index的位置
def printx(elem:Int): Unit ={
println(elem)
}
ab.+= (3)//增加数据
ab.append(2,2,2)
ab.insert(3,8)
ab(5)=213
ab.foreach(printx)
1.3可变数组与不可变数组的转化
package Chap03JiHe
import scala.collection.mutable.ArrayBuffer
/*
arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
(1)arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
(2)arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化
*/
object Test04ArrayChange {
def main(args: Array[String]): Unit = {
var arr1 = ArrayBuffer[Int](1,2,3,4)
var arr2 = Array[Int](3,4,5,76,34,1,23)
val buffer = arr2.toBuffer
val array = arr1.toArray
//arr1.clear() 说明没变
arr1.foreach(printx)
println()
arr2.foreach(printx)
println()
buffer.foreach(printx)
println()
array.foreach(printx)
}
}
1.4二(多)维数组
val tarr = Array.ofDim[Int](3,5)//二维数组
tarr(1)(2) = 1313
//二维数组是由,数组加数组构成,即第一次返回值是Array 、第二次才是int
for (elem <- tarr) {
for (elem <- elem) {
print(elem)
}
println()
}
2.List
2.1不可变List
val list = List(1,2,3,4,5)
val list5 = 1::2::3::4::Nil
list5.foreach(printx)
println()
val list1 = 7::6::5::list
list1.foreach(printx)
println()
var list2 = list.+:(5) //在末尾加上5
var list3 = 5::list //在前面加上5
list2.foreach(printx)
println()
list3.foreach(printx)
val list4 = list:::list3 //拼接
println()
list4.foreach(printx)
2.2可变List- ListBuffer
val lb = ListBuffer(1,2,3,45,5)
lb.append(3,4,5)
lb.insert(3,4444)
lb.foreach(printx)
lb(2) = 232332
lb.update(5,222222)
lb.-=(1)
//lb.-(3)
lb.remove(2,5)
println()
lb.foreach(printx)
3.Set
3.1不可变Set
package Chap03JiHe
/*
默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用
scala.collection.mutable.Set 包
(1)Set 默认是不可变集合,数据无序
(2)数据不可重复
(3)遍历集合
*/
object Test08SetInit {
def main(args: Array[String]): Unit = {
val set = Set(1,2,3,4,5,6)
val set1 = Set(1,2,3,4,5,6,3)
for(x<-set1){
println(x)
}
}
}
3.2可变Set
package Chap03JiHe
import scala.collection.mutable
object Test09MutableSet {
def main(args: Array[String]): Unit = {
val mset = mutable.Set(1,2,3,4,5,6)
mset += 8
//(4)向集合中添加元素,返回一个新的 Set
val ints = mset.+(9)
println(ints)
println("set2=" + mset)
mset -= (5)
mset.foreach(println)
println(mset.mkString(","))
}
}
4.Map
4.1不可变Map
package Chap03JiHe
import scala.collection.mutable
/*
Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射
*/
object Test10Map {
def main(args: Array[String]): Unit = {
val map = Map( "a"->1, "b"->2, "c"->3 )
//map.keys直接拿到所有的keys
for (elem <- map.keys){
println(elem+"="+map.get(elem))//直接使用get会返回Option类型
println(elem+"="+map.get(elem).get)
}
println(map.get("d").getOrElse(0))
//拿到的是一个Array[String]? //通过后面的学习我们知道,这就是一个元组
println(map("a")) //类似数组一样也可以访问 底层hashcode寻址。
map.foreach((a) => {println(a)})
map.foreach((a) => {println(a._1+"-"+a._2)})
val mmap = mutable.Map( "a"->1, "b"->2, "c"->3 )
val mmap2 = mutable.Map( "aaaa"->1, "b"->233, "adasd"->3 )
//(3)向集合增加数据
mmap+=("d"->4)
mmap+=(("e",333)) //两个括号
// 将数值 4 添加到集合,并把集合中原值 1 返回
val maybeInt: Option[Int] = mmap.put("a", 4)
println(maybeInt.getOrElse(0))
//(4)删除数据
//map.remove(key)
mmap-=("b", "c")
//(5)修改数据
mmap.update("d",5)
mmap("d") = 5
mmap.foreach((kv)=>{println(kv)})
mmap.foreach((kv)=>{println(kv._1+"-"+kv._2)})
//合并两个可变map
mmap ++= mmap2 //直接添加,若重复 覆盖。 后续在训练wordcount时,不会使用这样的方式
println(mmap)
}
}
4.2可变Map
package Chap03JiHe
import scala.collection.mutable
object MutableMap {
def main(args: Array[String]): Unit = {
val map = mutable.Map( "a"->1, "b"->2, "c"->3 )
//(3)向集合增加数据
map+=("d"->4)
// 将数值 4 添加到集合,并把集合中原值 1 返回
val maybeInt: Option[Int] = map.put("a", 4)
println(maybeInt.getOrElse(0))
//(4)删除数据
map.-=("b", "c")
//(5)修改数据
map.update("d",5)
map("d") = 5
map.foreach((kv)=>{println(kv)})
map.foreach((kv)=>{println(kv._1+"-"+kv._2)})
}
}
5.元组
package Chap03JiHe
/*
直接看成一个复杂的键值对类型也可。
元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就
是将多个无关的数据封装为一个整体,称为元组。
注意:元组中最大只能有 22 个元素。
*/
object Test11YuanZu {
def main(args: Array[String]): Unit = {
var tuple =(40,"bobo",true)
println(tuple._2)
println(tuple._1)
println(tuple._3)
println(tuple.productElement(2))
for(elem <- tuple.productIterator){
println(elem)
}
//(3)Map 中的键值对其实就是元组,只不过元组的元素个数为 2,称之为对偶
val map = Map("a"->1, "b"->2, "c"->3)
val map1 = Map(("a",1), ("b",2), ("c",3))
map.foreach(tuple=>{println(tuple._1 + "=" + tuple._2)})
}
}
6.对集合操作的函数
6.1基础函数
package Chap03JiHe
object Test12BasicFuction {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
//(1)获取集合长度
println(list.length)
//(2)获取集合大小,等同于 length
println(list.size)
//(3)循环遍历
list.foreach(println)
//(4)迭代器
for (elem <- list.iterator) {
println(elem)
}
//(5)生成字符串
println(list.mkString(","))
//(6)是否包含
println(list.contains(3))
package Chap03JiHe
object Test13YanSheng {
def main(args: Array[String]): Unit = {
val list1 = List[Int](1,2,3,4,5,6,7)
val list2 = List[Int](1,2,3,4,5,6,7,8,9,10)
println(list1.head)
//(2)获取集合的尾(不是头的就是尾)故尾巴是 2,3,4,5,6,7
println(list1.tail)
println(list1.tails)//返回的是迭代器
println(list1.init)
println(list1.reverse)
println(list1.take(3))
println(list1.takeRight(3))
println(list1.drop(3))
println(list1.dropRight(3))
//(8)并集
println(list1.union(list2))
//(9)交集
println(list1.intersect(list2))
//(10)差集
println(list1.diff(list2))
//(11)拉链 注:如果两个集合的元素个数不相等,那么会将同等数量的数据进
// 行拉链,多余的数据省略不用
println(list1.zip(list2))
//滑窗?
list1.sliding(2, 5).foreach(println)
}
}
}
}
6.2排序
package Chap03JiHe
object Test14ListSort {
def main(args: Array[String]): Unit = {
val list: List[Int] = List(1, 5, -3, 4, 2, -7, 6)
//(1)求和
println(list.sum)
//(2)求乘积
println(list.product)
//(3)最大值
println(list.max)
//(4)最小值
println(list.min)
//(5)排序
// (5.1)按照元素大小排序
println(list.sortBy(x => x))
// (5.2)按照元素的绝对值大小排序
println(list.sortBy(x => x.abs))
// (5.3)按元素大小升序排序
println(list.sortWith((x, y) => x < y))
// (5.4)按元素大小降序排序
println(list.sortWith((x, y) => x > y))
/*
(1)sorted
对一个集合进行自然排序,通过传递隐式的 Ordering
(2)sortBy
对一个属性或多个属性进行排序,通过它的类型。
(3)sortWith
基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。
*/
}
}
6.3复杂函数,大量用于MR
package Chap03JiHe
/*
(1)过滤
遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
(2)转化/映射(map)
将集合中的每一个元素映射到某一个函数
(3)扁平化
(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作
集合中的每个元素的子元素映射到某个函数并返回新集合
(5)分组(group)
按照指定的规则对集合的元素进行分组
(6)简化(归约)
(7)折叠
*/
object Test15HarderFuc {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val nestedList = List(List(1, 2, 3), List(4,5, 6), List(7, 8, 9))
val wordList = List("hello world", "hello atguigu", "hello scala")
//(1)过滤 filter 返回boolean 处理map
println(list.filter(x => x % 2 == 0))
//(2)转化/映射
println(list.map(x => x + 1))
println(list.map( x => x * 2))
//(3)扁平化
println(nestedList.flatten)
//(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten 操作
val value = wordList.map( _.split(" ") )
println(value)
val flatten = value.flatten
println(flatten)
println(wordList.flatMap(x => x.split(" ")))
//(5)分组
println(list.groupBy(x => x % 2))
}
}
package Chap03JiHe
object Test16HarderFuc2Reduce {//mr里 reduce就是归并起来。
def main(args: Array[String]): Unit = {
val list = List(1,2,3,4)
//1. (A1,A1) => A1
println(list.reduce(_+_)) //底层调用的是reduceleft
print("=======================")
val list2 = List(3,4,5,8,10)
println(list2.reduce(_-_)) //3-4-5-8-10 = -24
println(list2.reduceRight(_-_)) //这句话=> 3-(4-(5-(8-10))) 递归执行reduceleft
//底层是递归
/* 与视频中的源码不同,重新改了写法,看最后一句即可。
def reduceRight[B >: A](op: (A, B) => B): B = {
val it = iterator
if (it.isEmpty)
throw new UnsupportedOperationException("empty.reduceRight")
reversed.reduceLeft[B]((x, y) => op(y, x))
}
*/
}
}
6.4Fold
package Chap03JiHe
import scala.math.Fractional.Implicits.infixFractionalOps
object Test17Fold {
/*
新的源码比之前的好理解,直接不停的调用聚合。即跟着迭代器,每迭代一个进行一次计算。
给如的z 是一个初始值。
def foldLeft[B](z: B)(op: (B, A) => B): B = {
var result = z
val it = iterator
while (it.hasNext) {
result = op(result, it.next())
}
result
}
*/
def main(args: Array[String]): Unit = {
val list = List(3,4,5,8,10)
println(list.fold(10)(_*_))
println(list.foldLeft(10)(_-_))
println(list.foldRight(10)(_-_)) //=> 3-(4-(5-(8-(10-10)
/* override def foldRight[B](z: B)(op: (A, B) => B): B =
reverse.foldLeft(z)((right, left) => op(left, right))
与ReduceRight类似 无限递归
*/
}
}
6.5MergeMap
package Chap03JiHe
import scala.collection.mutable
object Test18Merge_map {
def main(args: Array[String]): Unit = {
val map1 =Map("a" -> 1 ,"b" ->3,"c"->22)
val map2 =mutable.Map("a" -> 23 ,"b" ->13,"c"->2,"d"->11,"e"->3)
//类似wordcount里map好了我们需要reduce
//def foldLeft[B](z: B)(op: (B, A) => B): B = 返回值是B 即一个map A是kv对
val map3 = map1.foldLeft(map2)(
(mergedMap,kv) => {
val key = kv._1
val value = kv._2
// mergedMap(key) = mergedMap.getOrElse(key, 0)+value
mergedMap.put(key,mergedMap.getOrElse(key,0)+value)
println(mergedMap)//
mergedMap
}
)
println(map3)
}
/*
HashMap(a -> 24, b -> 13, c -> 2, d -> 11, e -> 3)
HashMap(a -> 24, b -> 16, c -> 2, d -> 11, e -> 3)
HashMap(a -> 24, b -> 16, c -> 24, d -> 11, e -> 3)
HashMap(a -> 24, b -> 16, c -> 24, d -> 11, e -> 3)
说明此时的mergdmap初始值是map2 ,然后map1进来 加进去
所以此时map1是可以是死map 而map2必须是mutable
*/
}
7.WordCount案例演示
package Chap03JiHe
object Test17_ComWordCount {
def main(args: Array[String]): Unit = {
val stringlist: List[String] =List("hello","hello world","hello scala",
"hello spark from scala","hello flink from scala")
//切分
// val wordList1: List[Array[String]] = stringlist.map(_.split(" "))
// println(wordList1)//五个Array[String]
// //初始值应当是一个空的元
// val wordList2 = wordList1.flatten
// println(wordList2)
val wordlist: List[String] = stringlist.flatMap(_.split(" "))
//分组操作
val groupMap: Map[String, List[String]] = wordlist.groupBy(word => word)
println(groupMap)
//分组之后对list取长度
val wordcount: Map[String, Int] = groupMap.map(kv => (kv._1, kv._2.length))
println(wordcount)
//转换成list 排序取前三
val sortList: List[(String, Int)] = wordcount.toList
.sortWith(_._2 > _._2)
.take(3)
println(sortList)
}
}
WordCount高级案例
package Chap03JiHe
import scala.collection.MapView
object Test18CompleWordCount {
def main(args: Array[String]): Unit = {
//此时相当于maptask已经返回了几个预处理过的计算 我们现在需要对其进行一个reduce合并。
val tuplelist: List[(String, Int)] = List(
("hello", 3),
("hello world", 4),
("hello scala", 2),
("hello spark from scala", 6),
("hello flink from scala", 9)
)
//直接展开,然后再按照key合并最后排序输出
val newStringList: List[String] = tuplelist.map(
kv => {
(kv._1.trim + " ") * kv._2
}
)
println(newStringList)
/*val flattenMap: Map[String, List[String]] = newStringList.flatten(_.split(" ")).groupBy(k => k)
println(flattenMap)
val stringIntMap: Map[String, Int] = flattenMap.map(
kv => {
(kv._1, kv._2.length)
}
)
println(stringIntMap)
val resultList: List[(String, Int)] = stringIntMap.toList.sortWith(_._2 > _._2).take(3)
println(resultList)*/
val res: List[(String, Int)] = newStringList
.flatMap(_.split(" "))
.groupBy(k => k)
.map(kv => (kv._1, kv._2.length))
.toList
.sortWith(_._2 > _._2)
.take(3)
//过于复杂了,
println(res)
//思路2:直接基于预统计的结果进行转换
val preCountList: List[(String, Int)] = tuplelist.flatMap(
kv => {
val strings: Array[String] = kv._1.split(" ")
strings.map(string => (string, kv._2)) //返回的成了Array[(String,Int)] 就已经可以了因为会帮你扁平化
}
)
println(preCountList)
//对元祖进行聚合
val preCountMap: Map[String, List[(String, Int)]] = preCountList.groupBy(kv => kv._1)
//把value值叠加
val countMap: MapView[String, Int] = preCountMap.mapValues(list => list.map(_._2).sum)
println(countMap.toMap.toList.sortWith(_._2 > _._2))
}
}