scala-集合

集合

可變和不可變集合

根據容器中元素的組織方式和操作方式,可以分為有序和無序、可變和不可變等不同容器類別。

不可變集合:是指集合的元素一但初始化完成就不可在進行更改,任何對集合的改變都將生成一個新的集合。

可變集合:提供了改變集合內元素的方法;

Scala同時支持可變集合和不可變集合,主要下面兩個包:

  • scala.collection.mutable:定義了可變集合的特質和具體實現類
  • scala.collection.immutable:定義了不可變集合的特質和具體實現類

對于所有的集合類,Scala都同時提供了可變和不可變的版本

Scala優(yōu)先采用不可變集合,不可變集合元素不可變更,可以安全的并發(fā)訪問。Scala集合有三大類:Seq(序列)、Set(集)、Map(映射);所有集合都拓展Iterable特質


可變和不可變集合1.png

Immutable 不可變集合

可變和不可變集合2.png

mutable可變集合:

可變和不可變集合3.png
小結:
String 屬于IndexedSeq
Queue隊列和Stack堆這兩個經典的數據結構屬于LinearSeq
Map體系下有一個SortedMap,說明Scala中的Map是可以支持排序的
mutable可變集合中Seq中的Buffer下有ListBuffer,想當于List
List列表屬于Seq重的LinearSeq

Seq

Seq代表按照一定順序排列的元素序列,該序列是一種特殊的課迭代集合,包含可重復的元素。元素的順序是確定的,每個元素對應一個索引值。

Seq提供了兩個重要的子特質:

  • IndexedSeq:提供了快速隨機訪問元素的功能,它通過索引來查找和定位的
  • LinearSeq:提供了訪問head、tail的功能,它是線型的,有頭部和尾部的概念,通過遍歷來查找。

List

List代表元素固定的不可變列表,它是Seq的子類,在Scala中經常使用。List是函數式編程語言中典型的數據結構,與數組類似,可索引、存放類型相同的元素。List一旦被定義,其值就不能修改。

List列表有頭部和尾部的概念,可以分別使用head和tail方法來獲?。?/p>

  • head返回的是列表第一個元素的值
  • tail返回的是除第一個元素外的其它元素構成的新列表

這體現出列表具有遞歸的鏈表結構。

Scala定義了一個空列表對象Nil,定義為List[Nothing]

借助 Nil 可將多個元素用操作符 :: 添加到列表頭部,常用來初始化列表;

操作符 ::: 用于拼接兩個列表;

package hhb.cn.part09

/**
 * @description:
 * @date: 2020-09-28 22:06
 **/
object ListDemo {

  def main(args: Array[String]): Unit = {

    //Nil 表示一個空列表
    // :: 操作符表示向集合中添加元素,它是從右向左運算的,所以空集合一定放在最右邊
    val list1 = 1 :: 2 :: 3 :: 4 :: Nil
    val list2 = 5 :: 6 :: 7 :: 8 :: Nil
    // 使用 ::: 將兩個集合拼接起來
    val list3 = list1 ::: list2 // List(1, 2, 3, 4, 5, 6, 7, 8)
    val list4 = list1 :: list2 // List(List(1, 2, 3, 4), 5, 6, 7, 8)
    println(list3)
    println(list4)

    println(list3.head) //返回第一個元素
    println(list3.tail) //返回除了一個元素之外的所有元素
    println(list3.init) // 返回除了最后一個的所有元素
    println(list3.last) // 返回最后一個元素

    val list = List(5, 1, 3, 6, 2, 5, 7, 0)
    println(quickSort(list))
  }

  //遞歸,快排
  def quickSort(list: List[Int]): List[Int] = {
    list match {
      case Nil => Nil
      case head :: tail =>
        // 使用partition 方法,把list集合分為兩個部分,第一個部分小于head,第二個部分大于head
        val tuple: (List[Int], List[Int]) = tail.partition(_ < head)
        //讓小于head的部分放在頭部,把head放到大于head的集合中,組成一個新的集合
        quickSort(tuple._1) ::: head :: quickSort(tuple._2)
      //        val value = head :: Nil
      //        quickSort(tuple._1) ::: value ::: quickSort(tuple._2)
    }
  }
}

Queue

隊列Queue是一個先進先出的結構。

隊列是一個有序列表,在底層可以用數組或鏈表來實現。

先進先出的原則,就是先存入的數據,要先取出,后存入的數據后取出。

在Scala中,有scala.collection.mutable.Queue(可變集合)和scala.collection.immutable.Queue(不可變集合),一般來說,我們使用的是scala.collection.mutable.Queue

package hhb.cn.part09

import scala.collection.mutable

/**
 * @description:
 * @date: 2020-09-28 22:43
 **/
object QueueDemo {

  def main(args: Array[String]): Unit = {

    val queue = new mutable.Queue[Int]()
    println(queue)

    //添加一個元素
    queue += 1

    //向隊列中添加一個集合
    queue ++= List(2, 3, 4)

    //獲取第一個元素并刪除
    val dequeue = queue.dequeue()
    println(dequeue)
    println(queue)

    //再次向隊列中添加元素
    queue.enqueue(5,6,7)

    //獲取第一個元素和最后一個元素
    println(queue.head)
    println(queue.last)
  }
}

Set

Set(集合)是沒有重復元素的對象集合,Set中的元素是唯一的;

Set分為可變的和不可變的集合;

默認情況下,使用的是不可變集合(引用 scala.collection.immutable.Set);

使用可變集合,需要引用 scala.collection.mutable.Set 包;

package hhb.cn.part09


/**
 * @description:
 * @date: 2020-09-28 23:03
 **/
object SetDemo {

  def main(args: Array[String]): Unit = {

    //創(chuàng)建一個set集合,默認是不可變的set集合
    val set = Set(1, 2, 3, 4, 5, 6)
    set.removedAll(Array(1))
    //由于是不可變集合,無法刪除
    println(set)

    //創(chuàng)建一個可變Set集合
    import scala.collection.mutable.Set

    val mutableSet = Set[Int]()
    println(mutableSet)
    mutableSet.add(1)
    mutableSet.addAll(Array(2, 3, 4, 5, 1))
    println(mutableSet)

    mutableSet.remove(1)
    println(mutableSet)

    //通過是有 += -= 進行增加刪除操作
    mutableSet += 8
    println(mutableSet)
    mutableSet -= 2
    println(mutableSet)

    //對set集合進行交集的操作,可是使用&符合或intersect
    println(Set(1, 2, 3) & Set(2, 3, 4)) // 2,3
    println(Set(1, 2, 3) intersect (Set(2, 3, 4))) // 2,3

    // 對set集合進行去并集的操作( ++ 、 |  、 union),會自動去重
    println(Set(1, 2, 3) ++ Set(2, 3, 4)) //1,2,3,4
    println(Set(1, 2, 3) | Set(2, 3, 4)) //1,2,3,4
    println(Set(1, 2, 3) union Set(2, 3, 4)) //1,2,3,4

    //對Set集合進行取差集的操作( --  &~  diff)
    // 是將兩個集合中的相同的元素,從第一個集合中刪除掉,第一個集合剩下的元素就是取差集的結果
    println(Set(1, 2, 3) -- Set(2, 3, 4)) //1
    println(Set(1, 2, 3) &~ Set(2, 3, 4)) //1
    println(Set(1, 2, 3) diff Set(2, 3, 4)) //1
  }
}

Map

Map(映射)是一系列鍵值對的容器;Scala 提供了可變的和不可變的兩種版本的Map,

分別定義在包 scala.collection.mutable 和 scala.collection.immutable 里;

默認情況下,Scala中使用不可變的 Map;

如果要使用可變Map,必須導入scala.collection.mutable.Map;

在Map中,鍵的值是唯一的,可以根據鍵來對值進行快速的檢索。

package hhb.cn.part09

/**
 * @description:
 * @date: 2020-09-29 14:08
 **/
object MapDemo {

  def main(args: Array[String]): Unit = {
    //使用兩種方式創(chuàng)建不可變的Map

    val map1 = Map("a" -> 1, "b" -> 2)
    val map2 = Map(("a", 1), ("b", 2))

    map1.keys.foreach(println(_))
    map1.values.foreach(println(_))

    println(map1("b"))
    //如果訪問不存在的Key的時候,拋出異常
    //    println(map1("c"))

    //使用get方法,獲取與key對應的value值
    //get方法會返回一個Option對象,要么是some(有值),要么是none(無值)
    println(map1.get("b"))
    println(map1.get("c"))
    val num = map1.get("a")
    num match {
      case None => println("Null")
      case Some(x) => println(x)
    }

    //使用getOrElse方法,獲取key值對應的value的值,如果不存在,返回默認值
    println(map1.getOrElse("c", 0))
    println(map1.getOrElse("b", 0))


    //創(chuàng)建一個可變的Map
    val map3 = scala.collection.mutable.Map("a" -> 1, "b" -> 2)
    println(map3)
    map3("a") = 10
    println(map3)
    map3("c") = 3
    println(map3)
    //使用+= -= 添加刪除操作
    map3 += ("d" -> 4, "f" -> 5)
    println(map3)
    map3 -= ("d", "f")
    println(map3)

    //將key與value的值互換
    val map4 = for ((k, v) <- map3) yield (v, k)
    println(map4)

    //第二中方式將key和value互換
    //推薦使用該方式將key和value進行互換
    val map5 = map3.map(x => (x._2, x._1))
    println(map5)

    //通過拉鏈操作創(chuàng)建Map
    var a = Array(1, 2, 3)
    val b = Array("a", "b", "c")
    val c: Array[(Int, String)] = a.zip(b)
    val map6 = a.zip(b).toMap
    println(map6)
  }
}

集合常用算子

map、foreach & mapValues

集合對象都有 foreach、map 算子。

兩個算子的共同點在于:都是用于遍歷集合對象,并對每一項執(zhí)行指定的方法;

兩個算子的差異點在于:

foreach無返回值(準確說返回void),用于遍歷集合

map返回集合對象,用于將一個集合轉換成另一個集合

//map\forEach\mapValues
val list = (1 to 10).toList
list.foreach(elem => print(elem + " \t"))
list.foreach(print(_))
list.foreach(print)
println(list.map(_ > 2))
println(list.map(_ + 2))

操作 Map集合時,mapValues用于遍歷value,是map操作的一種簡化形式;

 // Range(20, 0, -2)用給定的步長值設定一個范圍,從開始到結束(不包含)。
val index = Range(20, 0, -2).zipWithIndex
val map = index.toMap
println(map)

//將map中的值+100
println(map.map(x => (x._1, x._2 + 100)))
println(map.map { case (key, vale) => (key, vale + 100) })
println(map.mapValues(_ + 100).toMap)

flatten & flatMap

flatten的作用是把嵌套的結構展開,把結果放到一個集合中;

在 flatMap 中傳入一個函數,該函數對每個輸入都返回一個集合(而不是一個元素),最后把生成的多個集合“拍扁”成為一個集合;

scala> val lst1 = List(List(1,2), List(3,4))
lst1: List[List[Int]] = List(List(1, 2), List(3, 4))

scala> lst1.flatten
res5: List[Int] = List(1, 2, 3, 4)

// flatten 把一個字符串的集合展開為一個字符集合,因為字符串本身就是字符的集合
scala> val lst4 = List("Java", "hadoop")
lst4: List[String] = List(Java, hadoop)

scala> lst4.flatten
res8: List[Char] = List(J, a, v, a, h, a, d, o, o, p)

// flatten 有效的處理 Some 和 None 組成的集合。它可以展開Some元素形成一個新的集合,同時去掉None元素
scala> val x = Array(Some(1), None, Some(3), None)
x: Array[Option[Int]] = Array(Some(1), None, Some(3), None)

// 方法很多,flatten最簡單
scala> x.flatten
res9: Array[Int] = Array(1, 3)

scala> x.collect{case Some(i) => i}
res10: Array[Int] = Array(1, 3)

scala> x.filter(!_.isEmpty).map(_.get)
res11: Array[Int] = Array(1, 3)
// 下面兩條語句等價
val lst = List(List(1,2,5,6),List(3,4))

// 將 lst 中每個元素乘2,最后作為一個集合返回
// 此時 flatMap = flatten + map
//List(1,2,5,6,3,4)
lst.flatten.map(_*2)
lst.flatMap((x: List[Int]) => x.map(_*2))
lst.flatMap(_.map(_*2))

// 將字符串數組按空格切分,轉換為單詞數組
val lines = Array("Apache Spark has an advanced DAG execution engine",
"Spark offers over 80 high-level operators")
// 下面兩條語句效果等價
//map算子產生的結果:Array(Array(Apache, Spark, has, an, advanced, DAG, execution, engine), Array(Spark, offers, over, 80, high-level, operators))
// flatten算子產生的結果:Array(Apache, Spark, has, an, advanced, DAG, execution, engine, Spark, offers, over, 80, high-level, operators)
lines.map(_.split(" ")).flatten
// 此時 flatMap = map + flatten 
lines.flatMap(_.split(" "))

備注:flatMap = flatten + map 或 flatMap = map + flatten

collect

collect通過執(zhí)行一個并行計算(偏函數),得到一個新的數組對象

object CollectDemo {
  //通過下面的偏函數,把chars數組的小寫a轉換為大寫的A
  val fun: PartialFunction[Char, Char] = {
    case 'a' => 'A'
    case x => x
  }

  def main(args: Array[String]): Unit = {
    val chars = Array('a', 'b', 'c')
    val newchars = chars.collect(fun)
    println("newchars:" + newchars.mkString(","))
  }
}

reduce

reduce可以對集合當中的元素進行歸約操作;

還有 reduceLeft 和 reduceRight ,reduceLeft 從左向右歸約,reduceRight 從右向左歸約;

val lst1 = (1 to 10).toList
lst1.reduce(_+_)

// 為什么這里能出現兩個占位符?
lst1.reduce(_+_)

// 我們說過一個占位符代表一個參數,那么兩個占位符就代表兩個參數。根據這個思路改寫等價的語句
// x類似于buffer,緩存每次操作的數據;y每次操作傳遞新的集合元素
lst1.reduce((x, y) => x + y)


// 利用reduce操作,查找 lst1 中的最大值
lst1.reduce((x,y) => if (x>y) x else y)

// reduceLeft、reduceRight
lst1.reduceLeft((x,y) => if (x>y) x else y)
lst1.reduceRight((x,y) => if (x>y) x else y)

sorted sortwith & sortby

Scala中對于集合的排序有三種方法:sorted、sortBy、sortWith

object SortDemo {
  def main(args: Array[String]): Unit = {
    val list = List(1, 9, 3, 8, 5, 6)
    //sorted方法對一個集合進行自然排序
    //sorted源碼:def sorted[B >: A](implicit ord: Ordering[B]): Repr
    //源碼中有兩點值得注意的地方:
    // 1.sorted方法中有個隱式參數ord: Ordering。
    // 2.sorted方法真正排序的邏輯是調用的java.util.Arrays.sort
    val numSort: List[Int] = list.sorted
    println(numSort)
    //sortBy源碼:def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr = sorted(ord on f)
    //sortBy最后調用的sorted方法
    println(list.sortBy(x => x).reverse)

    //sortWith源碼:def sortWith(lt: (A, A) => Boolean): Repr = sorted(Ordering fromLessThan lt)
    print(list.sortWith(_ > _))
  }
}

與Java集合的轉換

使用 scala.collection.JavaConverters 與Java集合交互。它有一系列的隱式轉換,添加了asJava和asScala的轉換方法。

import scala.collection.JavaConverters._
 
val list: Java.util.List[Int] = List(1,2,3,4).asJava
val buffer: scala.collection.mutable.Buffer[Int] = list.asScala
第八個模塊錯題集.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容