Scala学习(七)集合

112 阅读8分钟

集合

  1. Scala的集合有三大类:序列Seq,集Set,映射Map,所有的集合都扩展自Iterable特质

  2. 对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本,分别位于以下两个包

    • 不可变集合:scala.collection.immutable
    • 可变集合:scala.collection.mutable
  3. Scala不可变集合,就是指该集合对象不可修改,每次修改就会返回一个新对象,而不会对原对象进行修改。类似于java中的String对象 在这里插入图片描述

    • IndexedSeq是通过索引来查找和定位,因此速度快,比如String就是一个索引集合,通过索引即可定位
    • LinearSeq是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找
  4. 可变集合,就是这个集合可以直接对原对象进行修改,而不会返回新的对象。类似于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))

集合计算高级函数

  1. 过滤:遍历一个集合并从中获取满足指定条件的元素组成一个新的集合
  2. 转化/映射 map : 将集合中的每一个元素映射到某一个函数
  3. 扁平化
  4. 扁平化 + 映射
  5. 分组:按照指定的规则对集合的元素进行分组
  6. 简化(归约)
  7. 折叠
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案例

  1. 简单版本的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(" "))
  1. 复杂版本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)