集合
-
Scala的集合有三大类:序列Seq,集Set,映射Map,所有的集合都扩展自Iterable特质
-
对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本,分别位于以下两个包
- 不可变集合:scala.collection.immutable
- 可变集合:scala.collection.mutable
-
Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象
- IndexedSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位
- LinearSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
-
可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于Java中的StringBuilder对象
数组
不可变数组
- 第一种定义数组:
val arrl = new Array[Int](10)
- new 是关键字
- [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any
- (10),表示数组的大小,确定后就不可以变化
- 第二种定义数组:
val arr1 = Array(1, 2)
- 在定义数组时,直接赋初始值
- 使用apply方法创建数组对象
- 代码:
object test5 {
def main(args: Array[String]): Unit = {
//1. 第一种方式创建数组
val arr = new Array[Int](5)
//2. 第二种方式创建数组
val arr2 = Array.apply(1,2,3,4,5)
val arr3 = Array(1,2,3,4,5)
//3. 赋值元素
arr(0) = 1
arr(1) = 2
arr(2) = 3
arr(3) = 4
arr(4) = 5
//4. 访问元素
println(arr(0))
println(arr(1))
println(arr(2))
println(arr(3))
println(arr(4))
//5. 循环遍历数组
//方式一
for (i <- 0 until arr.length){
println(arr(i))
}
//方式二
for(i <- arr.indices){
println(arr(i))
}
//方式三 直接遍历所有元素
for (elem <- arr2){
println(elem)
}
//方式四 迭代器
val iter = arr2.iterator
while (iter.hasNext)
println(iter.next())
//方式五 调用foreach
arr2.foreach((elem:Int) => println(elem))
arr2.foreach(println)
println(arr2.mkString(" "))
//6. 添加元素
val arr4 = arr2:+(6)
println(arr4.mkString(" "))
val arr5 = arr4.+:(0)
//val arr5 = 0 +: arr4
println(arr5.mkString(" "))
val arr6 = -2 +: -1 +: arr5 :+ 7
println(arr6.mkString(" "))
}
}
可变数组
- 定义可变数组:
val arr01 = ArrayBuffer[Any](3, 2, 5)
- [Any]存放任意数据类型
- (3, 2, 5)初始化好的三个元素
- ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
- 不可变数组跟可变数组之间的转换
- 代码:
import scala.collection.mutable.ArrayBuffer
object test5 {
def main(args: Array[String]): Unit = {
//1. 创建可变数组
val arr1:ArrayBuffer[Int] = new ArrayBuffer[Int]()
val arr2 = ArrayBuffer(1,2,3,4,5)
//2. 访问元素
println(arr1.mkString(" "))
println(arr2)
println(arr2(0))
//3. 赋值元素
arr2(0) = 0
//4. 添加元素
arr1 += 1
println(arr1.mkString(" "))
0 +=: arr1
println(arr1.mkString(" "))
arr1.append(2,3)
println(arr1.mkString(" "))
arr1.prepend(-2,-1)
println(arr1.mkString(" "))
arr1.insert(6, 4,5)
println(arr1.mkString(" "))
//5. 删除元素
arr1.remove(0)
println(arr1.mkString(" "))
arr1.remove(0,2)
println(arr1.mkString(" "))
arr1 -= 5
println(arr1.mkString(" "))
//6. 将可变数组转变为不可变数组
val arr:Array[Int] = arr1.toArray
println(arr)
//7.不可变数组转变为可变数组
var arr3 = arr.toBuffer[Int]
println(arr3)
}
}
多维数组
- 定义多维数组:
val arr = Array.ofDim[Double](3,4)
- 代码:
//1. 创建多维数组
val array:Array[Array[Int]] = Array.ofDim[Int](2,2)
//2. 访问元素
array(0)(1) = 19
array(1)(0) = 25
//3. 遍历数组
println(array.mkString(" "))
for (i <- 0 until array.length; j <- 0 until array(i).length){
println(array(i)(j))
}
array.foreach(l => l.foreach(println))
列表List
不可变List
- 说明:
- List 默认为不可变集合
- 创建一个List(数据有顺序,可重复)
- 遍历List
- List增加数据
- 集合间合并:将一个整体拆成一个一个的个体,称为扁平化
- 取指定数据
- 空集合Nill
- 代码:
//1. 创建一个List集合
val list = List(1,2,3)
println(list)
//2. 访问元素
println(list(0))
list.foreach(println)
//3. 添加元素
val list1 = list :+ 10
var list2 = 23 +: list1
println(list1.mkString(" "))
println(list2.mkString(" "))
//4. 创建一个新的列表
val list3 = Nil.::(13)
println(list3.mkString(" "))
val list4 = 32 :: 31 :: 30 :: Nil
println(list4.mkString(" "))
val list5 = list3 ::: list4
println(list5.mkString(" "))
val list6 = list5 ++ list4
println(list6.mkString(" "))
可变ListBuffer
- 说明:
- 创建一个可变集合ListBuffer
- 向集合中添加数据
- 打印集合数据
- 代码:
//1. 创建可变列表
val list1: ListBuffer[Int] = new ListBuffer[Int]()
val list2 = ListBuffer(1,2,3,4)
println(list1.mkString(" "))
println(list2.mkString(" "))
//2. 添加元素
list1.append(15,62)
list2.prepend(20)
list1.insert(1, 19, 22)
println(list1.mkString(" "))
list1 += 45 += 11
println(list1.mkString(" "))
31 +=: 96 +=: list1 += 25 += 11
println(list1.mkString(" "))
val list3 = list2 ++ list1
println(list1.mkString(" "))
println(list2.mkString(" "))
println(list3.mkString(" "))
//4. 修改元素
list2(3) = 30
println(list2.mkString(" "))
//5. 删除元素
list2.remove(2)
list2 -= 20
println(list2.mkString(" "))
Set集合
不可变Set
- 说明:
- Set默认是不可变集合,数据无序
- 数据不可重复
- 遍历集合
- 代码:
//1. 创建Set
val set1 = Set(1,1,2,3,4)
println(set1.mkString(" "))
//2. 添加元素
val set2 = set1.+(20)
// set2 = set1 + 20
//val set2 = set1 + 20
println(set1.mkString(" "))
println(set2.mkString(" "))
//3. 合并集合
val set = Set(5,6,7,8)
val set3 = set1 ++ set
println(set3.mkString(" "))
//4. 删除集合
val set5 = set3 - 1
println(set5.mkString(" "))
可变Set
- 说明:
- 创建可变集合 mutable.Set
- 打印集合
- 集合添加元素
- 向集合中添加元素,返回一个新的 Set
- 删除数据
- 代码:
//1. 创建set
var set1:mutable.Set[Int] = mutable.Set(1,2,3,4)
println(set1.mkString(" "))
//2. 添加元素
set1 += 11
set1.add(10)
println(set1.mkString(" "))
//3. 删除元素
set1 -= 11
set1.remove(10)
println(set1.mkString(" "))
//4. 合并两个set
val set2 = mutable.Set(5,6,7,8)
val set4 = set2 ++ set1
set1 ++= set4
println(set4.mkString(" "))
println(set1.mkString(" "))
Map集合
不可变Map
- 说明
- 创建不可变集合 Map
- 循环打印
- 访问数据
- 如果 key 不存在,返回 0
//1. 创建Map集合
val map:Map[String, Int] = Map("a" -> 13, "b" -> 14)
println(map)
println(map.mkString(" "))
//2. 遍历元素
map.foreach(println)
map.foreach((kv:(String,Int)) => println(kv))
//3. 取map中所有的key或者value
for(key <- map.keys){
println(s"$key ${map.get(key)}")
}
//4. 访问某一个key的value
println(map.get("a").get)//不够安全
println(map.getOrElse("a", 0))
可变Map
- 说明
- 创建可变集合
- 打印集合
- 向集合增加数据
- 删除数据
- 修改数据
//1. 创建可变Map
val map = mutable.Map("a" -> 1, "b" -> 2)
println(map.mkString(" "))
//2. 添加元素
map.put("c",3)
println(map)
map += (("d",4))
println(map)
//3. 删除元素
map.remove("d")
map -= ("c")
println(map)
//4. 修改元素
map.update("a",3)
map.update("b",4)
println(map)
//5. 合并两个Map
val map2 = Map("c" -> 5, "d" -> 6)
map ++= map2
println(map2)
println(map)
元组
- 说明:元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据,就是将多个无关的数据封装为一个整体,称为元组
- 元组最大只能有22个元素
//1. 创建元组
val tuple:(String, Int, Char, Boolean) = ("hello", 12, 'a', true)
println(tuple)
//2. 访问数据
println(tuple._1)
//3. 遍历元组数据
for (elem <- tuple.productIterator){
println(elem)
}
//4. 嵌套元组
val mulTuple = (12, 0.3, "hello", (23,"2131"), 29)
println(mulTuple._4._2)
集合常用函数
基本属性和常用操作
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))
衍生集合
val list1: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
val list2: List[Int] = List(4, 5, 6, 7, 8, 9, 10)
//(1)获取集合的头
println(list1.head)
//(2)获取集合的尾(不是头的就是尾)
println(list1.tail)
//(3)集合最后一个数据
println(list1.last)
//(4)集合初始数据(不包含最后一个)
println(list1.init)
//(5)反转
println(list1.reverse)
//(6)取前(后)n 个元素
println(list1.take(3))
println(list1.takeRight(3))
//(7)去掉前(后)n 个元素
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))
//(12)滑窗
list1.sliding(2, 5).foreach(println)
集合计算初级函数
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)排序
//sortBy 对一个属性或多个属性进行排序,通过它的类型。
// (5.1)按照元素大小排序
println(list.sortBy(x => x))
// (5.2)按照元素的绝对值大小排序
println(list.sortBy(x => x.abs))
// sortWith 基于函数的排序,通过一个 comparator 函数,实现自定义排序的逻辑。
// (5.3)按元素大小升序排序
println(list.sortWith((x, y) => x < y))
// (5.4)按元素大小降序排序
println(list.sortWith((x, y) => x > y))
集合计算高级函数
- 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
- 转化/映射 map : 将集合中的每一个元素映射到某一个函数
- 扁平化
- 扁平化 + 映射
- 分组:按照指定的规则对集合的元素进行分组
- 简化(归约)
- 折叠
val list: 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
atguigu", "hello scala")
//(1)过滤
println(list.filter(x => x % 2 == 0))
//(2)转化/映射
println(list.map(x => x + 1))
//(3)扁平化
println(nestedList.flatten)
//(4)扁平化+映射 注:flatMap 相当于先进行 map 操作,在进行 flatten
操作
println(wordList.flatMap(x => x.split(" ")))
//(5)分组
println(list.groupBy(x => x % 2))
// (6) 归约
val list = List(1,2,3,4)
// 将数据两两结合,实现运算规则
val i: Int = list.reduce( (x,y) => x-y )
println("i = " + i)
// 从源码的角度,reduce 底层调用的其实就是 reduceLeft
//val i1 = list.reduceLeft((x,y) => x-y)
// ((4-3)-2-1) = -2
val i2 = list.reduceRight((x,y) => x-y)
println(i2)
// (7)转化
val list = List(1,2,3,4)
// fold 方法使用了函数柯里化,存在两个参数列表
// 第一个参数列表为 : 零值(初始值)
// 第二个参数列表为: 简化规则
// fold 底层其实为 foldLeft
val i = list.foldLeft(1)((x,y)=>x-y)
val i1 = list.foldRight(10)((x,y)=>x-y)
println(i)
println(i1)
// 两个 Map 的数据合并
val map1 = mutable.Map("a"->1, "b"->2, "c"->3)
val map2 = mutable.Map("a"->4, "b"->5, "d"->6)
val map3: mutable.Map[String, Int] = map2.foldLeft(map1)
{
(map, kv) => {
val k = kv._1
val v = kv._2
map(k) = map.getOrElse(k, 0) + v
map
}
}
println(map3)
普通的wordCout案例
- 简单版本的WordCount案例:将计算单词数量
//wordCount案例
val stringList = List(
"hello",
"hello world",
"hello scala",
"hello spark from scala",
"hello flink from scala"
);
//1. 对字符串进行切分,得到一个打散所有单词的列表
/*
val wordList1 = stringList.map(_.split(" "))
val wordList2 = wordList1.flatten
*/
val wordList1 = stringList.flatMap(_.split(" "))
println(wordList1.mkString(" "))
//2. 相同的单词进行分组
val groupMap:Map[String, List[String]] = wordList1.groupBy( word => word )
println(groupMap.mkString(" "))
//3. 分组之后的对单词进行个数
val countMap:Map[String, Int] = groupMap.map( kv => (kv._1, kv._2.length))
println(countMap.mkString(" "))
//4. 将map转换成List,排序取前三
val sortedList:List[(String, Int)] = countMap.toList.sortWith( _._2 > _._2).take(3)
println(sortedList.mkString(" "))
- 复杂版本WordCount案例
//复杂的WordCount案例
// 第一种方式(不通用)
val tupleList = List(("Hello Scala Spark World ", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
val stringList: List[String] = tupleList.map(t => (t._1 + "") * t._2)
//val words: List[String] =
stringList.flatMap(s => s.split(" "))
val words: List[String] = stringList.flatMap(_.split(" "))
//在 map 中,如果传进来什么就返回什么,不要用_省略
val groupMap: Map[String, List[String]] =
words.groupBy(word => word)
//val groupMap: Map[String, List[String]] =
words.groupBy(_)
// (word, list) => (word, count)
val wordToCount: Map[String, Int] = groupMap.map(t => (t._1,
t._2.size))
val wordCountList: List[(String, Int)] =
wordToCount.toList.sortWith {
(left, right) => {
left._2 > right._2
}
}.take(3)
//tupleList.map(t=>(t._1 + " ") * t._2).flatMap(_.split("
")).groupBy(word=>word).map(t=>(t._1, t._2.size))
println(wordCountList)
//第二种
val tuples = List(("Hello Scala Spark World", 4), ("Hello Scala Spark", 3), ("Hello Scala", 2), ("Hello", 1))
// (Hello,4),(Scala,4),(Spark,4),(World,4)
// (Hello,3),(Scala,3),(Spark,3)
// (Hello,2),(Scala,2)
// (Hello,1)
val wordToCountList: List[(String, Int)] = tuples.flatMap {
t => {
val strings: Array[String] = t._1.split(" ")
strings.map(word => (word, t._2))
}
}
// Hello, List((Hello,4), (Hello,3), (Hello,2), (Hello,1))
// Scala, List((Scala,4), (Scala,3), (Scala,2)
// Spark, List((Spark,4), (Spark,3)
// Word, List((Word,4))
val wordToTupleMap: Map[String, List[(String, Int)]] =
wordToCountList.groupBy(t => t._1)
val stringToInts: Map[String, List[Int]] =
wordToTupleMap.mapValues {
datas => datas.map(t => t._2)
}
stringToInts
/*
val wordToCountMap: Map[String, List[Int]] =
wordToTupleMap.map {
t => {
(t._1, t._2.map(t1 => t1._2))
}
}
val wordToTotalCountMap: Map[String, Int] =
wordToCountMap.map(t=>(t._1, t._2.sum))
println(wordToTotalCountMap)
*/
队列
- Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue。
val que = new mutable.Queue[String]()
que.enqueue("a", "b", "c")
println(que.dequeue())
println(que.dequeue())
println(que.dequeue())
并行集合
- Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算。
val result1 = (0 to 100).map{case _ =>
Thread.currentThread.getName}
val result2 = (0 to 100).par.map{case _ =>
Thread.currentThread.getName}
println(result1)
println(result2)