Scala中的集合

一、Scala集合基础

说明:

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

二、不可变集合

不可变集合继承图

 

 

 说明:

  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是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找。

三、可变集合

可变集合继承图

 

 

 四、数组

4.1 不可变数组

数组定义;

  1. 第一种,例如:val arr1 = new Array[Int](10)
    1. [Int]是指定可以存放的数据类型,如果希望存放任意数据类型,则指定Any 
    2. (10),表示数组的大小,确定后就不可以变化。
  2. 第二种,例如:val arr1 = Array(1, 2) 
    1. 在定义数组时,直接赋初始值 
    2. 使用apply方法创建数组对象

代码示例:

def main(args: Array[String]): Unit = {
    //创建数组
    val array = new Array[Int](4)
    //查看数组,可以看到数组的默认值都是0
    println(array.mkString(","))
    //数组赋值
    array(3) = 10
    //采用update方法给数组赋值,格式:update(index,value)
    array.update(0,1)
    println(array.mkString(","))

    //普通遍历数组
    for (i <- array){
      print(i + " ")
    }
    println()

    //简化遍历
    array.foreach(println(_))
    //因为只有一个参数,可以在把_也简化
    array.foreach(println)

    //增加元素
    //因为是不可变数组,故增加元素就是产生新的数组
    val array2: Array[Int] = array :+ 5
    array2.foreach(println)
    
  }
//调用apply方法创建数组
    val array3:Array[Int] = Array(1,2,3)
    array3.foreach(println)

4.2 可变数组

说明:

  1. 格式,如:val arr01 = ArrayBuffer[Any](3, 2, 5) ;
  2. ArrayBuffer需要引入scala.collection.mutable.ArrayBuffer ;
  3. ArrayBuffer是有序的集合 ;
  4. 增加元素使用的是append方法(),支持可变参数 。

代码示例:

  def main(args: Array[String]): Unit = {
    val buffer = ArrayBuffer[Any](1, 2, 3, "hello")
    //遍历
    buffer.foreach(println)
    println("------------------------")
    //追加数据
    buffer += 4

    //向数据最后添加数据
    buffer.append(5,6)

    //像数组指定位置增加数据 insert(index,Any*)
    buffer.insert(0,7,8)

    //修改第一个元素的值
    buffer(0) = 10
    buffer.foreach(println)
  }

4.3 不可变数组和可变数组的转换

说明;

arr2.toArray:返回结果才是一个不可变数组,arr2本身没有变化

arr1.toBuffer:返回结果才是一个可变数组,arr1本身没有变化 。

4.4 多维数组

例如;定义一个三行四列的数组:

val arr = Array.ofDim[Double](3,4) 

五、List列表

5.1 不可变List

 说明:

  1. List默认为不可变集合 ;
  2. 集合间合并:将一个整体拆成一个一个的个体,称为扁平化 ;
  3. 构造列表的两个基本单位是 Nil 和 ::
  4. 可以使用 ::: 运算符或 List.:::() 方法或 List.concat() 方法来连接两个或多个列表;
  5. 可以使用 List.fill() 方法来创建一个指定重复数量的元素列表,如List.fill(10)(2),重复2十次;
  6. List.tabulate() 方法是通过给定的函数来创建列表。方法的第一个参数为元素的数量,可以是二维的,第二个参数为指定的函数,我们通过指定的函数计算结果并返回值插入到列表中:
    object Test {
       def main(args: Array[String]) {
          // 通过给定的函数创建 6 个元素,n是从0开始计算的
          val squares = List.tabulate(6)(n => n * n)
          println( "一维 : " + squares  )
    
          // 创建二维列表
          val mul = List.tabulate( 4,5 )( _ * _ )      
          println( "多维 : " + mul  )
       }
    }
  7. List.reverse 用于将列表的顺序反转;
  8. 为列表预添加元素:如
    val y = 2 +: x
  9. 在列表开头添加元素
    val y = 2 :: x
  10. 将列表的所有元素添加到 StringBuilder,格式:def addString(b: StringBuilder)
  11. 将列表的所有元素添加到 StringBuilder,并指定分隔符,格式:def addString(b: StringBuilder, sep: String)
  12. 通过列表索引获取元素:格式:def apply(n: Int)
  13. 检测列表中是否包含指定的元素,格式:def contains(elem: Any): Boolean
  14. 将列表的元素复制到数组中:def copyToArray(xs: Array[A], start: Int, len: Int): Unit
  15. 去除列表的重复元素,并返回新列表:def distinct: List[A]
  16. 丢弃前n个元素,并返回新列表:def drop(n: Int): List[A]
  17. 丢弃最后n个元素,并返回新列表:def dropRight(n: Int): List[A]
  18. 从左向右丢弃元素,直到条件p不成立:def dropWhile(p: (A) => Boolean): List[A]
  19. 检测列表是否以指定序列结尾:def endsWith[B](that: Seq[B]): Boolean
  20. 更多方法查看官网API:Scala Standard Library 2.12.15 - scala.collection.immutable.List (scala-lang.org)

示例代码:

  def main(args: Array[String]): Unit = {
    //默认为不可变集合
    val list:List[Int] = List(1,2,3,4,3)
//等价于 val list = 1::2::3::4::3::Nil
//增加数据 val list1 = 5::list //在列表后添加元素 val list2 = list1 :+2 //在列表前添加元素 val list3 = 0 +: list2 //两个列表合并 val list4 = list2 ::: list3 //遍历输出 list4.foreach(println) }

 

5.2 可变ListBuffer

  def main(args: Array[String]): Unit = {
    //使用apply方法,创建一个ListBuffer
    val list = ListBuffer(1,2,3,4)

    //向集合添加元素
    list += 5
    list.append(6)
    //insert(index,value*)
    list.insert(6,7,8)
    list.foreach(print)
    //apply:根据列表索引获取元素
//    println(list.apply(3))
    println("\n-----------------")
    //修改列表元素
    list(0) = 0
    //update(index,value)
    list.update(1,10)
    list.foreach(print)
    println("\n-----------------")
    //删除指定数据
    list -= 10
    list.foreach(print)
    println("\n-----------------")
    //删除指定位置的数据
    list.remove(1)
    list.foreach(print)
  }
}

 

六、Set集合

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

6.1 不可变Set

 说明:

  1. Set默认是不可变集合,数据无序 ;
  2. 数据不可重复。
//输出的数据无序
val set = Set(1,2,3,4,5)
set.foreach(print)

6.2 可变mutable.Set

  def main(args: Array[String]): Unit = {
    val set = Set(1,2,3,4,5)
    set.foreach(print)
    println("\n---------------------")

    //创建可变Set集合
    val set2 = mutable.Set(2,4,1,5,6)
    //添加元素并返回一个新的Set集合
    val set3 = set2 .+(0)
    //删除数据
    set3 -= 6
    set3.foreach(print)
    println("\n---------------------")
    //使用分隔符将列表所有元素作为字符串显示
    println(set3.mkString(","))
  }

 

七、Map结合

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

7.1 不可变Map

def main(args: Array[String]): Unit = {
    //创建不可变Map集合
    val map = Map(1 ->"a",2->"b",3->"c",4->"d")
    println(map)
    for (elem <- map.keys){
      //使用get访问map集合的数据,会返回特殊类型Option(选项):有值(Some),无值(None)
      //例:map.get(elem) 返回的结果为:1 = some(a)
      println(elem + "=" + map.get(elem).get)
    }
    //使用getOrElse方法,查询map中是否有key值5,如果不存在返回0;
    //如果存在则返回其value值
    println(map.getOrElse(5,0))
  }

7.2 可变Map

  def main(args: Array[String]): Unit = {
    //创建不可变Map集合
    val map = Map(1 ->"a",2->"b",3->"c",4->"d")
    println(map)
    for (elem <- map.keys){
      //使用get访问map集合的数据,会返回特殊类型Option(选项):有值(Some),无值(None)
      //例:map.get(elem) 返回的结果为:1 = some(a)
      println(elem + "=" + map.get(elem).get)
    }
    //使用getOrElse方法,查询map中是否有key值5,如果不存在返回0;
    //如果存在则返回其value值
    println(map.getOrElse(5,0))

    //创建不可变Map集合
    val map2 = mutable.Map(1 ->"a",2->"b",3->"c",4->"d")
    //向集合添加数据
    map2 += (5->"e")
    //使用put方法,若集合中存在该key值,则更新其value
    //若不存在,则添加key-value
    map2.put(1,"x")
    map2.put(6,"z")

    //修改数据
    map2.update(1,"a")
    println(map2)
  }

八、元组

元组也是可以理解为一个容器,可以存放各种相同或不同类型的数据。说的简单点,就是将多个无关的数据封装为一个整体,称为元组。

注意:元组中最大只能有22个元素。 

说明:

  • 声明元组的方式:(元素1,元素2,元素3) ;
  • Map中的键值对其实就是元组,只不过元组的元素个数为2,称之为对偶 。
  def main(args: Array[String]): Unit = {
    //声明元组的方式:(元素1,元素2,元素3)
    val tuple:(Int,String,Boolean) = (10,"hello",true)

    //访问元组,调用方式: _顺序号
    //注意:顺序号从1开始
    println(tuple._2) //hello

    //通过索引访问元素
    //注意:索引从0开始
    println(tuple.productElement(0))

    //通过迭代器访问数据
    for(x <- tuple.productIterator){
      println(x)
    }
  }

九、队列

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

 def main(args: Array[String]): Unit = {
    //创建一个队列
    val q = mutable.Queue[String]()
    //入队
    q.enqueue("a")
    q.enqueue("b")
    //出队
    q.dequeue()
    println(q)
  }

十、并行集合

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

1、将普通集合转为并行集合

//格式:arr.par
(1 to 5).foreach(println(_))
//转为并行集合
(1 to 5).par.foreach(println(_))

2、获取到参与并行计算的线程

(0 to 10000).collect{case _ => Thread.currentThread.getName}.distinct

(0 to 10000).par.collect{case _ => Thread.currentThread.getName}.distinct

3、fold(折叠)在并行计算中

//fold说明:
//fold方法需要传入两个参数,第一个参数是初始值,第二个参数是一个函数,函数也需要两个参数
//0作为第二个函数参数z的第一个值,根据这个函数体累加numbers集合中的元素
val numbers = List(5, 4, 8, 6, 2)
numbers.fold(0) { (z, i) =>
  z + i
}
// result = 25
注意:arr.fold(0)(_+_)与reduce(聚合函数)的区别是有初始值,当初始值为0,效果一样
arr.par.fold:在并行计算要注意!几个线程就会加进去几个初始值
posted @ 2022-02-14 14:54  干了这瓶老干妈  阅读(160)  评论(0编辑  收藏  举报
Live2D