Scala基础(三)
Scala-集合
简介
说明
- 集合三大类:序列(seq)、集(set)、映射(map),所有的集合都拓展自iterable特质
- 对于几乎所有的集合类,Scala都提供了可变和不变的版本,分别位于scala.collection.immutable(不可变集合)、scala.collection.mutable(可变集合)两个包下。
不可变集合
Scala中的不可变集合,由于Scala的基本单元是对象,因此这的不可变指代的是集合对象不可变,每次改变原对象不变,会返回一个新的对象
可变集合
可变集合是直接对原本的对象做修改,不会返回新的对象。
通性操作
- 所有集合通用的添加[+:、:+、+=、+=:、++、++:、++=、++=:]/删除[-、-=、--、--=]方法区别:
- 带+与带-的区别:
- 带+是添加元素
- 带-是删除元素
- 一个+/-与两个+/-的区别:
- 一个+/-是添加/删除单个元素
- 两个+/-是添加/删除一个集合所有元素
- 带冒号与冒号在前、冒号在后的区别:
- 冒号在前是将元素添加在集合最末尾
- 冒号在后是将元素添加在集合最前面
- 带冒号是将元素添加在集合最末尾
- 带=与不带=的区别:
- 带=是修改集合本身
- 不带=是生成新集合,原集合没有改变
- update与updated的区别:
- update是修改集合本身元素
- updated是生成新集合,原集合元素没有改变
- 带+与带-的区别:
数组
不可变数组
通过new方式: new Array [ 元素类型 ] ( 数组的长度)
通过apply方法: Array[ 元素类型 ] ( 初始元素,... )<常用>
代码演示
//1、通过new方式: new Array[元素类型](数组的长度)
val arr = new Array[Int](5)
println(arr.toList)
//2、通过apply方法: Array[元素类型](初始元素,...)
val arr2 = Array[Int](10,3,2,6,5)
println(arr2.toList)
//添加元素
//添加单个元素
val arr3 = arr2.+:(20)
println(arr2.toList)
println(arr3.toList)
println(arr2)
println(arr3)
val arr4 = arr2.:+(30)
println(arr4.toList)
//添加一个集合所有元素
val arr5 = arr2.++(Array(100,300,400))
println(arr5.toList)
val arr6 = arr2.++:(Array(100,300,400))
println(arr6.toList)
//删除
//获取指定角标元素
println(arr6(0))
//修改指定角标元素
arr6(0)=1000
println(arr6.toList)
for(element<- arr6){
println(element)
}
//不可变数组转可变数组
val arr11 = arr6.toBuffer
println(arr11)
可变数组
通过new方式: new ArrayBuffer[ 元素类型 ] ()
通过apply方法: ArrayBuffer[ 元素类型 ] (初始元素,...)
代码演示
//通过new方式: new ArrayBuffer[元素类型]()
val arr1 = new ArrayBuffer[Int]()
//通过apply方法: ArrayBuffer[元素类型](初始元素,...)
val arr = ArrayBuffer[Int](10,3,2,6,7)
println(arr1)
println(arr)
//添加元素
//添加单个元素
val arr2 = arr.+:(30)
val arr3 = arr.:+(40)
println(arr2)
println(arr3)
println(arr)
arr.+=(50)
println(arr)
arr.+=:(60)
println(arr)
//添加一个集合所有元素
val arr7 = arr.++(Array(20,30,40))
println(arr7)
val arr8 = arr.++:(Array(20,30,40))
println(arr8)
arr.++=(Array(20,30,40))
println(arr)
arr.++=:(Array(60,70,80))
println(arr)
println("-----------------------")
println(arr)
arr.insert(2,100,200,300)
println(arr)
//删除元素
val arr9 = arr.-(60)
println(arr9)
println(arr)
arr.-=(60)
println(arr)
val arr10 = arr.--(Array(10,20,30,4,5,6,7))
println(arr10)
arr.--=(Array(60,70,80))
println(arr)
arr.remove(2,3)
println(arr)
//更新角标数据: 数组名(角标) = 值
arr(0)=1000
println(arr)
//获取角标数据: 数组名(角标)
println(arr(0))
//可变数组转不可变数组
val arr11 = arr.toArray
println(arr11)
//多维数组
val arr12 = Array.ofDim[Int](2,3)
println(arr12.length)
println(arr12(0).length)
数组转换
arr1.toBuffer //不可长数组转可变数组
arr2.toArray //可变数组转不可变数组
- arr2.toArray返回结果才是一个不可变数组,arr2本身没有变化
- arr1.toBuffer返回结果才是一个可变数组,arr1本身没有变化
seq集合(List)
不可变List
创建方法
- 通过apply方法创建: List[ 元素类型 ] ( 初始元素,....)
- 通过 :: 方法创建: 初始元素 :: 初始元素 :: ... :: Nil/不可变List 或者 list.::(初始元素)
- :: 最右边必须是Nil或者是不可变List
- Nil其实可以当做一个空的不可变List, Nil一般用作给不可变List变量赋予初始值,Nil与不可变List的关系类似Null与String
- Nil给不可变List变量赋予初始值的时候,变量类型必须指定。
添加元素方法:
:: 是添加单个元素[类似之前不带=的一个+的方法]
::: 是添加一个集合所有元素[类似之前不带=的两个的方法]
代码演示
//通过apply方法创建: List[元素类型](初始元素,....)
val list1 = List[Int](10,2,5,4,3)
//通过 :: 方法创建:
val list2 = 2 :: 3 :: 4 :: 5 :: Nil
println(list1)
println(list2)
println(Nil)
//var list3 = Nil
//list3 = list2
//添加元素
val list3 = list2.+:(10)
println(list3)
val list4 = list2.:+(20)
println(list4)
val list5 = list2.::(30)
println(list5)
val list6 = list2.++(List(100,33,22))
println(list6)
val list7 = list2.++:(Array(44,55,66))
println(list7)
//扁平化处理
val list8 = list2.:::(List(66,77,88))
println(list8)
//获取角标元素
println(list8(0))
//修改指定角标元素
val list9 = list8.updated(0,666)
println(list8)
println(list9)
//不可变List转可变
println(list9.toBuffer)
可变List创建
- 通过apply方法: ListBuffer[元素类型](初始元素,..
- 通过new方式: new ListBuffer[元素类型] ()
代码演示
//通过apply方法: ListBuffer[元素类型](初始元素,....)
val list1 = ListBuffer[Int](10,3,2,6,7)
val list2 = new ListBuffer[Int]()
println(list1)
println(list2)
//添加元素
val list3 = list1.:+(20)
println(list3)
val list4 = list1.+:(30)
println(list4)
list1.+=(40)
println(list1)
list1.+=:(50)
println(list1)
list1.insert(2,60,70)
println(list1)
val list5 = list1.++(List(100,22,33))
println(list5)
val list6 = list1.++:(List(11,44,77))
println(list6)
list1.++=(List(444,555,666))
println(list1)
list1.++=:(List(777,888,999))
println(list1)
//删除
val list7 = list1.-(10)
println(list7)
list1.-=(999)
println(list1)
val list8 = list1.--(List(3,2,6,7,10))
println(list8)
list1.--=(List(3,2,6,7,10))
println(list1)
list1.remove(2,4)
println(list1)
//获取指定角标元素
println(list1(0))
//修改指定角标元素
list1(0)=100
println(list1)
//可变List转不可变List
println(list1.toList)
set集合
不可变set
不可变Set的创建: immutable.Set[元素类型] (初始元素,....)
set的特性:无序,不重复
代码演示
//不可变Set的创建: immutable.Set[元素类型](初始元素,....)
val set = Set[Int](10,10,2,4,7,6,2)
println(set)
//添加元素
val set2 = set.+(50)
println(set2)
val set3 = set.++(List(100,300,200,33))
println(set3)
val set4 = set.++:(List(100,300,200,33))
println(set4)
//删除元素
val set5 = set.-(2)
println(set5)
val list6 = set.--(List(7,4))
println(list6)
可变set
可变Set创建: mutable.Set[元素类型] (初始元素,....)
代码演示
val set = mutable.Set[Int](10,3,2,6,7)
println(set)
//添加元素
val set2 = set.+(20)
set.+=(30)
println(set2)
println(set)
val set3 = set.++(List(33,11,55,44))
val set4 = set.++:(List(33,11,55,44))
println(set3)
println(set4)
set.++=(List(77,888,33))
println(set)
set.add(100)
println(set)
//删除元素
val set6 = set.-(2)
println(set6)
set.-=(3)
println(set)
val set7 = set.--(List(6,7,77))
println(set7)
val set8 = set.--=(List(33,30,2))
println(set8)
println(set)
println(set.eq(set8))
set.remove(888)
println(set)
set.update(6,false)
println(set)
元组
元组的创建:
- 通过()创建: (初始元素,....)
- 通过->方式[只适用于创建二元元组]: K -> V
- scala中二元元组表示KV键值对
元组的注意点
-
元组最多只能存放22个元素
-
元组一旦定义,元素和长度都不可以改变
-
元组获取元素: 元组名._N [N是元素的角标,元组的角标从1开始]
代码演示
class Region(name:String,school:School)
class School(name:String,clazz:Clazz)
class Clazz(name:String, stu:Student)
class Student(name:String,age:Int)
Main:
//1、通过()创建: (初始元素,....)
val t1 = ("lisi",20,"shenzhen")
//2、通过->方式[只适用于创建二元元组]: K -> V
val t2 = "zhangsan" -> 100
println(t1)
println(t2)
println(t1._3)
val lines = Source.fromFile("datas/log.txt").getLines()
val logs = for(line<- lines) yield{
val arr = line.split("\t")
( arr(0) , arr(1), arr(2).toInt , arr(3) )
}
val list = List(
new Region("宝安区",new School("宝安中学",new Clazz("法师班",new Student("安其拉",20)))),
new Region("宝安区",new School("宝安中学",new Clazz("法师班",new Student("王昭君",18)))),
new Region("宝安区",new School("宝安中学",new Clazz("法师班",new Student("甄姬",16)))),
new Region("宝安区",new School("宝安中学",new Clazz("法师班",new Student("小乔",22))))
)
val list2 = List(
("宝安区",("宝安中学",("法师班",("安其拉",20)))),
("宝安区",("宝安中学",("法师班",("王昭君",20)))),
("宝安区",("宝安中学",("法师班",("甄姬",20)))),
("宝安区",("宝安中学",("法师班",("小乔",20))))
)
for( element<- list2 ) {
println( element._2._2._2._1 )
}
Map集合
不可变map
不可变Map创建
immutable.Map[K的类型,V的类型] ( (K,V), K->V,... )
需要注意的地方
- Option: 为了提醒外部当前结果有可能为空,需要自己处理
- Some: 代表不为空,结果封装在Some中,后续可以调用get方法获取结果
- None: 代表为空
map获取元素
getOrElse(key,默认值): 如果map中key存在则返回key对应的value值,如果key不存在则返回默认值
代码演示
val map = Map[String,Int]("aa"->10, ("bb",20),"ac"->30,"dc"->40,"cc"->60)
println(map)
//添加元素
val map2 = map.+( "cd"->100 )
println(map2)
val map3 = map.++( List( "ee"->70 ,"ff"->80) )
println(map3)
val map4 = map.++:(List( "gg"->200,"oo"->300))
println(map4)
//删除元素
val map5 = map.-("ac")
println(map5)
val map6 = map.--(List("cc","dc"))
println(map6)
//获取元素
//根据key获取value值
//println(map("ac1"))
//val option = map.get("ac1")
//if(!option.isEmpty){
// println(option.get)
//}
println(map.getOrElse("ac1", -1))
//获取所有的key
for( key<- map.keySet) println(key)
//获取所有的value值
for(value<- map.values) println(value)
//修改元素
val map11 = map.+( "aa"->100 )
println(map11)
val map12 = map.updated("aa",1000)
println(map12)
可变map
可变Map的创建: mutable.Map[K的类型,V的类型] ( K->V , (K,V),... )
代码演示
val map = mutable.Map[String,Int]("aa"->10,"cd"->20,"ad"->40)
println(map)
//添加元素
val map2 = map.+( "ee"->50 )
println(map2)
map.+=( "ff"->60 )
println(map)
val map3 = map.++(List("tt"->20,"pp"->30))
println(map3)
map.++=(List("oo"->30,"gg"->40))
println(map)
map.put("rr",100)
println(map)
//删除
val map5 = map.-("oo")
println(map5)
map.-=("gg")
println(map)
val map6 = map.--(List("rr","cd"))
println(map6)
map.--=(List("aa","cd","ad"))
println(map)
map.remove("oo")
println(map)
//获取元素
//根据key获取value值
println(map.getOrElse("ff", -1))
//获取所有的key
println(map.keys)
//获取value
println(map.values)
//修改value值
map("rr1")=2000
println(map)
map.put("gg",500)
println(map)
常用函数
基本属性和常用操作
- 获取集合长度
- 获取集合大小
- 循环遍历
- 迭代器
- 生成字符串
- 是否包含
代码演示
val list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)
//(1)获取集合长度
println(list.length)
//(2)获取集合大小
println(list.size)
//(3)循环遍历
list.foreach(println)
//(4)迭代器
for (elem <- list.iterator) {
println(elem)
}
//(5)生成字符串
println(list.mkString(","))
//(6)是否包含
println(list.contains(3))
衍生集合
- 获取集合的头head
- 获取集合的尾(不是头就是尾)tail
- 集合最后一个数据 last
- 集合初始数据(不包含最后一个)
- 反转
- 取前(后)n个元素
- 去掉前(后)n个元素
- 并集
- 交集
- 差集
- 拉链
- 滑窗
代码演示
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)排序
// (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))
集合计算高级函数
- 过滤
- 转化/映射
- 扁平化
- 扁平化+映射 注:flatMap相当于先进行map操作,在进行flatten操作
- 分组
- 简化(规约)
- 折叠
代码演示
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) reduce
// 将数据两两结合,实现运算规则
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) 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)
队列
- scala也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为enqueue和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)