Scala-集合

一、集合概述

1)Scala 的集合有三大类:序列 Seq、集 Set、映射 Map,所有的集合都扩展自 Iterable特质
2)对于几乎所有的集合类,Scala 都同时提供了可变和不可变的版本,分别位于以下两个包
不可变集合:scala.collection.immutable
可变集合: scala.collection.mutable
3)Scala 不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于 java 中的 String 对象
4)可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于 java 中 StringBuilder 对象

建议:在操作集合的时候,不可变用符号,可变用方法

不可变集合继承图:
在这里插入图片描述

1)Set、Map 是 Java 中也有的集合
2)Seq 是 Java 没有的,我们发现 List 归属到 Seq 了,因此这里的 List 就和 Java 不是同一个概念
3) for 循环中的 1 to 3,就是 IndexedSeq 下的 Range
4)String 也是属于 IndexedSeq
5)我们发现经典的数据结构比如 Queue 和 Stack 被归属到 LinearSeq(线性序列)
6)大家注意 Scala 中的 Map 体系有一个 SortedMap,说明 Scala 的 Map可以支持排序
7)IndexedSeq 和 LinearSeq 的区别:
(1)IndexedSeq是通过索引来查找和定位,因此速度快,比如 String 就是一个索引集合,通过索引即可定位
(2)LinearSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找

可变集合继承图:在这里插入图片描述

二、数组

2.1 不可变数组

1)第一种方式定义数组
定义:val arr1:Array = new Array[Int] (10)
(1)new 是关键字
(2)[Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定 Any
(3)(10),表示数组的大小,确定后就不可以变化

object TestArray{
 def main(args: Array[String]): Unit = {
 #(1)数组定义
 val arr01 = new Array[Int](4)# 声明了长度,数据默认是0
 println(arr01.length) // 4
 
 #(2)数组赋值
 //(2.1)修改某个元素的值
 arr01(3) = 10
 //(2.2)采用方法的形式给数组赋值
 arr01.update(0,1)
 
 #(3)遍历数组
 //(3.1)查看数组
 println(arr01.mkString(","))//使用,对元素进行连接
 //(3.2)普通for循环遍历
for(i<- 0 until arr01.length){
	println(arr01(i))
}
//增强for循环遍历
for(i<-arr01.indices) println(arr01(i))
for(elem<-arr01) println(arr01(i))
 //(3.3)foreach()方法遍历
arr01.foreach((x)=>{println(x)})
arr01.foreach(println)

 #(4)增加元素(由于创建的是不可变数组,增加元素,其实是产生新的数组)
val newArr1 = arr01.:+(73) // 在数组尾部增加一个元素
val newArr2 = arr01.+:(30) // 在数组头部增加一个元素

#Scala 提供了更简便的操作 -_-#
val new Arr3 = arr01 :+ 15 
val new Arr4 = 19 +: 29 +: arr01 :+ 25

#个人建议,: 比作数组本身
 }
}

2)第二种方式定义数组
val arr1 = Array(1, 2)
(1)在定义数组时,直接赋初始值
(2)使用 apply 方法创建数组对象

object TestArray{
 def main(args: Array[String]): Unit = {
 var arr02 = Array(1, 3, "bobo")
 println(arr02.length)
 for (i <- arr02) {
  println(i)
 }
 }
}

当使用 new 关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实是伴生对象的 apply 方法。
使用arr(i)访问数组元素实际上是使用了伴生对象的apply方法

不可变数组指的是数组的引用地址,数组被声明后,其地址大小不能改变,但是能改变其中的数值。

2.2 可变数组

1)定义变长数组
val arr01 = ArrayBuffer[Any](3, 2, 5)
(1)[Any]存放任意数据类型
(2)(3, 2, 5)初始化好的三个元素
(3)ArrayBuffer 需要引入 scala.collection.mutable.ArrayBuffer
(4)如果没有指定初始化元素ArrayBuffer默认长度16

import scala.collection.mutable.ArrayBuffer
object TestArrayBuffer {
 def main(args: Array[String]): Unit = {
 #(1)创建并初始赋值可变数组
 val arr01 = ArrayBuffer[Any](1, 2, 3)
 // val arr01 = ArrayBuffer()
 
 # (2) 遍历方式和不可变数组一样
 #(3)增加元素
 //可变数组不能够使用 :+ 的方式进行添加,该方式会产生新数组,适用于不可变数组
 //(3.1)追加数据
 arr01 += 4  //arr01 = arr01 + 4  向数组尾部添加
 5 +=: arr01 //向数组头部添加
 //(3.2)向数组最后追加数据
 arr01.append(5,6)
 //(3.3)向指定的位置插入数据
 arr01.insert(0,7,8) //下标为0的位置插入
 arr01.insertAll(下标,数组) //添加一个数组
 // (3.4) 向数组头部添加数据
 arr01.prepend(11,76)
 
 #(4)修改元素
  arr01(1) = 9 //修改第 2 个元素的值
  arr01.remove(下标)
  arr01.remove(起始下标,终止下标) //删除一段元素
  arr01 -= 3 #通过数值进行删除,如果元素值不存在则不进行更改
}

推荐使用不可变数组,防止有多个对象指向同一个数组地址。

2.3 不可变数组与可变数组的转换

arr1.toBuffer //不可变数组转可变数组
arr2.toArray //可变数组转不可变数组
(1)arr2.toArray 返回结果才是一个不可变数组,arr2 本身没有变化
(2)arr1.toBuffer 返回结果才是一个可变数组,arr1 本身没有变化

可变数组转不可变数组
val arr:ArrayBuffer[Int] = ArrayBuffer(23,56,98)
val newArr:Array[Int] = arr.toArray
不可变数组转可变数组
val Buffer:mutable.Buffer[Int] = newArr.toBuffer

2.4 多维数组

多维数组定义:
val arr = Array.ofDim[Double] (3,4)
说明:
1.二维数组中有三个一维数组,每个一维数组中有四个元素
2.最多支持5维数组

object DimArray {
 def main(args: Array[String]): Unit = {
 //(1)创建了一个二维数组, 有三个元素,每个元素是,含有 4 个元素一维数组()
 val arr = Array.ofDim[Int](3, 4)
 arr(1)(2) = 88
 //(2)遍历二维数组
 for( i<-arr.indices;j <- arr(i).indices){
	println(array(i)(j))
 }
array.foreach(line => line.foreach(println))

 }
}

三、列表List

3.1 不可变List

object TestList {
 def main(args: Array[String]): Unit = {
 //(1)List 默认为不可变集合
 //(2)创建一个 List(数据有顺序,可重复)
 val list: List[Int] = List(1,2,3,4,3)
 
 //(7)空集合 Nil
 val list5 = 1::2::3::4::Nil
 //(4)List 增加数据
 //(4.1)::的运算规则从右向左
 //val list1 = 5::list
 val list1 = 7::6::5::list
 //(4.2)添加到第一个元素位置
 val list2 = list.+:(5)
 //(5)集合间合并:将一个整体拆成一个一个的个体,称为扁平化
 val list3 = List(8,9)
 //val list4 = list3::list1
 val list4 = list3:::list1
 //(6)取指定数据
 println(list(0))
 //(3)遍历 List
 list5.foreach(println)
 }
}

Nil是一个空的集合
:: 是一个方法,能将左边元素添加到右边列表
::: 能够合并列表,将列表拆分后在相加可以使用++代替

3.2 可变List

import scala.collection.mutable.ListBuffer
object TestList {
 def main(args: Array[String]): Unit = {
 //(1)创建一个可变集合
 val buffer = ListBuffer(1,2,3,4)
 //(2)向集合中添加数据
 buffer.+=(5)
buffer.append(6)
buffer.insert(1,2)
 //(3)打印集合数据
 buffer.foreach(println)
//(4)修改数据
buffer(1) = 6
buffer.update(1,7)
//(5)删除数据
buffer.-(5)
buffer.-=(5)
buffer.remove(5)
// (6)合并集合
list1 ++=: list2 //改变的是list2
lsit3 = list1 ++ list2 //合并两个集合
 }
}

四、Set集合

默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用scala.collection.mutable.Set 包

4.1 不可变Set

(1)Set 默认是不可变集合,数据无序
(2)数据不可重复

object TestSet {
 def main(args: Array[String]): Unit = {
 //(1)Set 默认是不可变集合,数据无序
 val set = Set(1,2,3,4,5,6)
 //(2)数据不可重复
 val set1 = Set(1,2,3,4,5,6,3) #数据无序且不重复
 //(3)添加元素
 val set2 = set1.+ 20 //set1 + 20
 //(4)合并set
 val set3 = set1 ++ set2
 //(5)删除元素
 val set4 = set3 - 20
 }
}

Scala中通过包名区分不可变set和可变set

4.2 可变 mutable.Set

object TestSet {
 def main(args: Array[String]): Unit = {
 //(1)创建可变集合 
 //set是Scala中的一种特质,需要使用伴生对象创建
 val set = mutable.Set(1,2,3,4,5,6)
 //(3)集合添加元素
 set += 8 //底层还是调用的add
 set.add(8)//返回值是Boolean
 //(4)向集合中添加元素,返回一个新的 Set
 val set2 = set.+(9)
 println("set2=" + set)
 //(5)删除数据
 set-=(5)
 set.remove(3)
 //(2)打印集合
 set.foreach(println)
 println(set.mkString(","))
 //(6)合并集合
 val set4 = set ++ set2
 set1 ++= set2
 }
}

五、Map集合

Scala 中的 Map 和 Java 类似,也是一个散列表,它存储的内容也是键值对(key-value)映射

5.1 不可变Map

 //创建不可变map
    val map1:Map[String,Int]=Map("a"->13,"b"->25,"hello"->3)
    println(map1) //Map(a -> 13, b -> 25, hello -> 3)

    //遍历元素
    map1.foreach(println) //(a,13) (b,25) (hello,3)
    //map1.foreach((kv:(String,Int))=>println((kv)))

    //取出map中的key或value
    for(key<-map1.keys){  //a-->Some(13) b-->Some(25) hello-->Some(3)
      println(s"$key-->${map1.get(key)}")
    }

    //为了防止空指针异常,将value包装成了一个option类型,有数据时为some,空时为None
    //访问value
    println(map1.get("a").get) //13
    println(map1.get("aimyon"))//None
    //这种获取方式是不安全的,因为在编译时不知道get是否能获取到值
    //当一个key的vlaue为None时,使用get会出异常
    println(map1.getOrElse("aimyon","0")) //为None时为0
    println(map1("a")) //13

5.2 可变Map

	//创建可变map
    val map2: mutable.Map[String, Int] = mutable.Map("a" -> 13, "b" -> 25, "hello" -> 3)
    println(map2) //Map(a -> 13, b -> 25, hello -> 3)
    println(map2.getClass) //class.scala.collection.mutable.HashMap

    //添加元素
    map2.put("aimyon", 36)
    map2 += (("e", 6))
    println(map2) //Map(e -> 6, b -> 25, a -> 13, aimyon -> 36, hello -> 3)

    //删除元素
    map2.remove("e")
    println(map2.getOrElse("e", 0)) //0
    map2 -= "b"
    println(map2) //Map(a -> 13, aimyon -> 36, hello -> 3)

    //修改元素
    map2.update("c", 5)
    map2.update("a", 1)
    println(map2) //Map(a -> 1, c -> 5, aimyon -> 36, hello -> 3)

    //合并map
    val map3: Map[String, Int] = Map("aaa" -> 13, "bbb" -> 25, "hello world"  -> 3)
    map2 ++= map3 //map3是不可变的,map2为可变的   只能够将合并后的给map2
    print(map2) 
    //Map(bbb -> 25, aaa -> 13, a -> 1, hello world -> 3, c -> 5, aimyon -> 36, hello> 3)
    //合并后,会将相同的key覆盖

六、元组

元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组。
注意:元组中最大只能有 22 个元素。

//创建元组
    val tuple = ("hello",122,'a',true)
    println(tuple)
    
    //访问数据
    println(tuple._1) //hello
    println(tuple._3) // a
    println(tuple.productElement(2))// 122
    
    //遍历元组
    for (elem <- tuple.productIterator)
      println(elem)
    
    //嵌套元组
    val mulTuple = (12,0.3,"aimyon",(23,"scala"),29)
    println(mulTuple._4._2) //scala

七、集合的常用操作和基本属性

val list = List(1,3,4,5,6,36)
    val set = Set(23,34,51,66)

    //获取集合长度 or 大小
    println(list.length)  //只有线性序列(LinearSeq)才能获取length
    println(set.size) //所有集合类型都能使用size

    //循环遍历
    for(elem<-list)
      println(elem)
    //迭代器
    for(elem<-list.iterator)
      println(elem)

    //生成字符串
    println(list.mkString("--")) //1--3--4--5--6--36

    //是否包含某个元素
    println(list.contains(23)) //false
    println(set.contains(23)) //true

7.1 衍生集合的操作

衍生集合:一个集合经过一些操作后返回的新的集合

单集合操作:

	val list1 = List(1,3,5,7,2,89)
    val list2 = List(3,56,213,44,1,36)
    //获取集合的头 通常使用在有效的集合
    println(list1.head) //1
    //获取集合的尾  值的是除了head之外的元素
    println(list1.tail) //List(3, 5, 7, 2, 89)
    //获取最后一个元素
    println(list1.last) //89
    //获取集合初始数据
    println(list1.init) //List(1, 3, 5, 7, 2)
    //反转集合
    println(list1.reverse) //List(89, 2, 7, 5, 3, 1)
    //取出前(后)n个元素
    println(list1.take(3)) //前3个 List(1, 3, 5)
    println(list1.takeRight(4))//从右开始4个 List(5, 7, 2, 89)
    //去掉前(后)n个元素
    println(list1.drop(3)) //List(7, 2, 89)

两个集合操作:

	val list1 = List(1,3,5,7,2,89)
	val list2 = List(3,56,213,44,1,36)
	//并集  如果是set集合做并集操作(set1 ++ set2),元素将会去重,且无序
    val union = list1.union(list2)
    println(union)
    println(list1 ::: list2)
    //List(1, 3, 5, 7, 2, 89, 3, 56, 213, 44, 1, 36)

    //交集
    val intersection = list1.intersect(list2)
    println(intersection)
    //List(1,3)

    //差集,某个集合独有的元素
    val diff1 = list1.diff(list2)
    val diff2 = list2.diff(list1)
    println(diff1) //List(5, 7, 2, 89)
    println(diff2) //List(56, 213, 44, 36)

    //拉链,将左右两边的元素一一对应组合成二元组,多的将会被去除
    println("zip1:"+ list1.zip(list2))
    print("zip2:"+ list2.zip(list1))
    //zip1:List((1,3), (3,56), (5,213), (7,44), (2,1), (89,36))
    //zip2:List((3,1), (56,3), (213,5), (44,7), (1,2), (36,89))

    //滑窗 sliding(size,step)
    for (elem<-list1.sliding(3)){
      println(elem)
    }
    //List(3, 5, 7)
    //List(5, 7, 2)
    //List(7, 2, 89)

7.2 集合计算简单函数

 val list = List(5,1,82,-1,4)
    val list2 = List(("a",5),("b",3),("c",7),("d",-3),("e",22))

    //求和
    println(list.sum) //91
    //求乘积
    println(list.product) //-1640
    //最大值
    println(list.max) //82
    println(list2.max) //默认比较第一个元素,"e"的ASC码最大
    println(list2.maxBy((tuple:(String,Int))=>tuple._2))//传入一个方法取出要比较的元素
    //最小值
    println(list.min) // -1
    //从大到小逆序排序
    println(list.sorted.reverse)\
    //List(82, 5, 4, 1, -1)
    //传入隐式参数
    println(list.sorted(Ordering[Int].reverse))
    //List(82, 5, 4, 1, -1)
    //根据规则排序
    println(list.sortWith((a:Int,b:Int) => {a<b})) //从小到大排序
    //List(-1, 1, 4, 5, 82)

7.3 集合计算高级函数

(1)过滤
遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
(2)转化/映射(map)
将集合中的每一个元素映射到某一个函数
(3)扁平化
拆分元素,再合并成一个集合
(4)扁平化+映射
注:flatMap 相当于先进行 map 操作,在进行 flatten 操作集合中的每个元素的子元素映射到某个函数并返回新集合
(5)分组(group)
按照指定的规则对集合的元素进行分组
(6)简化(归约)
(7)折叠

Map类操作

val list = List(1,2,3,4,5,6,7,8,9,10)

    //过滤 偶数
    val evenList = list.filter(_%2==0) //(elem:Int) => {elem%2==0}
    println(evenList) //List(2, 4, 6, 8, 10)

    //map映射
    println(list.map(_*2)) //List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
    println(list.map(elem=>elem*elem)) //List(1, 4, 9, 16, 25, 36, 49, 64, 81, 100)

    //扁平化
    val nestedList:List[List[Int]] = List(List(1,2,3),List(6,5),List(6,7,8,9))
    val flatList = nestedList(0) ::: nestedList(1) ::: nestedList(2)
    val flatList2 = nestedList.flatten
    println(flatList2) //List(1, 2, 3, 6, 5, 6, 7, 8, 9)

    //扁平映射
    //将一组字符串进行分词,并保存成单词的列表
    val strings:List[String] = List("hello world","aimyon","ado")
    val splitList:List[Array[String]] = strings.map(_.split(" "))
    println(splitList) 
    //List([Ljava.lang.String;@58ceff1, [Ljava.lang.String;@7c30a502[Ljava.lang.String;@49e4cb85)
    val flattenList = splitList.flatten
    println(flattenList) //List(hello, world, aimyon, ado)
    val flatmapList = strings.flatMap(_.split(" "))
    println(flatmapList) //List(hello, world, aimyon, ado)

    //分组group by
    val groupMap = list.groupBy(_%2)
    val groupMap2 = list.groupBy(data =>{
      if(data % 2 == 0) "偶数" else "奇数"
    })
    println(groupMap)
    //Map(1 -> List(1, 3, 5, 7, 9), 0 -> List(2, 4, 6, 8, 10))
    println(groupMap2)
    //Map(奇数 -> List(1, 3, 5, 7, 9), 偶数 -> List(2, 4, 6, 8, 10))

Reduce类操作:

	val list = List(1,2,3,4,5,6,7,8,9,10)
	//从左到右两两归约 结果和sun相同
    println(list.reduce(_+_)) 
    println(list.reduceLeft(_+_))
    println(list.reduceRight(_+_))
    //上边结果都是55
    val list2 = List(3,4,5,8,10)
    println(list2.reduce(_-_)) //-24
    println(list2.reduceLeft(_-_)) //-24
    println(list2.reduceRight(_-_)) //6  3 -(4 - (5 - (8 -10)))

Fold折叠类操作:

	val list = List(1,2,3,4,5,6,7,8,9,10)
	//fold
    println(list.fold(10)(_+_)) //10+1+2+3+4+5... 65
    println(list.foldLeft(10)(_-_))// 10-1-2-3-4... -45
    println(list.foldRight(11)(_-_))//... 3-(4 - (5- (6-(7-...(10-11))))) 6

应用案例:

我们前边使用的Map合并,发现map1++map2中,如果存在相同的key值,map2会覆盖掉map1的value;
我们希望这种操作能做到相同的累加,不相同的添加。

val map1 = Map("a"->1,"b"->3,"c"->6)
    val map2 = mutable.Map("a"->6,"b"->2,"c"->8,"d"->3)
    println(map1++map2) //Map(a -> 6, b -> 2, c -> 8, d -> 3)

    val map3 = map1.foldLeft(map2)((mergedMap,kv)=>{
      val key = kv._1
      val value = kv._2
      mergedMap(key)=mergedMap.getOrElse(key,0) + value
      mergedMap
    })
    println(map3) //Map(b -> 5, d -> 3, a -> 7, c -> 14)

WordCount案例:

    val list:List[String]  = List("hello world","hello java","hello scala","hello flick from scala","hello")
    val wordList = list.flatMap(_.split(" "))

    val wordMap = wordList.groupBy(word => word)

    val groupWord = wordMap.map(kv => (kv._1,kv._2.length))

    val sortList = groupWord.toList.sortWith(_._2 >_._2)

    println(sortList)
    //List((hello,5), (scala,2), (world,1), (java,1), (from,1), (flick,1))

八、队列和并行集合

队列:
Scala 也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为 enqueue 和 dequeue。

object TestQueue {
 def main(args: Array[String]): Unit = {
 val que = new mutable.Queue[String]()
 que.enqueue("a", "b", "c")
 println(que.dequeue())//a
 println(que.dequeue())//b
 println(que.dequeue())//c
 //不可变队列
 val queue2 = Queue("A","V","C")
 val queue3 = queue2.enqueue("d")
 println(queue3)
 }
}

并行集合:
Scala 为了充分使用多核 CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算

object TestPar {
 def main(args: Array[String]): Unit = {
  val result1 = (0 to 100).map{case => 
Thread.currentThread.getName}
//Vector(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,1)
 val result2 = (0 to 100).par.map{case => 
Thread.currentThread.getName}
//ParVector(12, 12, 12, 18, 12, 12, 12, 12, 12,13,19,16)
 
 }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aimyon_36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值