1. 程式人生 > >Scala筆記整理(六):Scala集合庫

Scala筆記整理(六):Scala集合庫

大數據 Scala

[TOC]


Scala主要集合結構

1、Scala中的集合體系主要包括:IterableSeq(IndexSeq)Set(SortedSet)Map(SortedMap)。其中Iterable是所有集合trait的根trait。實際上Seq、Set、和Map都是子trait

  • Seq

    是一個有先後次序的值的序列,比如數組或列表。IndexSeq允許我們通過×××的下表快速的訪問任意元素。舉例來說,ArrayBuffer是帶下標的,但是鏈表不是。

  • Set

    是一組沒有先後次序的值。在SortedSet中,元素以某種排過序順序被訪問。

  • Map

    是一組(鍵、值)對偶。SortedMap按照鍵的排序訪問其中的實體。

2、 Scala中的集合是分成可變和不可變兩類集合的,其中可變集合就是說,集合的元素可以動態修改,而不可變集合的元素在初始化之後,就無法修改了。分別對應scala.collection.mutablescala.collection.immutable兩個包。

3、Seq下包含了RangeArrayBufferList等子trait。其中Range就代表了一個序列,通常可以使用“1 to10”這種語法來產生一個Range。 ArrayBuffer就類似於Java中的ArrayList。

List

List常用操作1

1、在Scala中,列表要麽是Nil(及空表),要麽是一個head元素加上一個tail,而tail又是一個列表

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

scala> list.head
res29: Int = 1

scala> list.tail
res30: List[Int] = List(2, 3, 4, 5)

scala> list.isEmpty
res31: Boolean = false

scala> list == Nil
res32: Boolean = false

下面是一個使用遞歸求list集合中和的例子:

def recursion(list:List[Int]):Int = {
    if(list.isEmpty) {
        return 0  // 使用return顯式結束程序的運行,否則0只是該if語句的返回值,並不會結束程序的運行,當然如果用else不用return也行
    }
    list.head + recursion(list.tail)
}

List常用操作2

增加

//增
/*  A.++(B)  --> 在列表A的尾部對添加另外一個列表B,組成一個新的列表
 *  A.++:(B) --> 在列表A的首部對添加另外一個列表B,組成一個新的列表
 *  A.:::(B) --> 在列表A的首部對添加另外一個列表B,組成一個新的列表
 *  ------
 *  A.:+ (element) -->在列表A的尾部添加一個element,組成一個新的集合
 *  A.+: (element) -->在列表A的首部添加一個element,組成一個新的集合
 *  A.:: (element) -->在列表A的首部添加一個element,組成一個新的集合
 */

測試如下:

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

scala> val right = List(5, 6, 7)
right: List[Int] = List(5, 6, 7)

scala> left.++(right)
res33: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> left.++:(right)
res34: List[Int] = List(5, 6, 7, 1, 2, 3, 4)

scala> left.:::(right)
res35: List[Int] = List(5, 6, 7, 1, 2, 3, 4)

scala> left.:+(10)
res36: List[Int] = List(1, 2, 3, 4, 10)

scala> left.+:(10)
res38: List[Int] = List(10, 1, 2, 3, 4)

scala> left.::(10)
res39: List[Int] = List(10, 1, 2, 3, 4)

刪除

drop(n)         --->刪除list的前n個元素(首部開始刪除)
dropRight(n)    --->刪除list的後n個元素(尾部開始刪除)
dropWhile(p: A => Boolean)  --->逐個匹配去除符合條件的元素,直到不符合條件,之後的元素不再判斷

測試如下:

scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list.drop(2)
res52: List[Int] = List(3, 4, 5, 6, 7)

scala> list.dropRight(3)
res53: List[Int] = List(1, 2, 3, 4)

scala> list.dropWhile(_ <= 3)
res54: List[Int] = List(4, 5, 6, 7)

scala> list.dropWhile(_ > 3)    // 第一個元素就不符合條件,後面的不再判斷,所以一個也沒有刪除
res55: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

修改與查詢

scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list(0)
res57: Int = 1

scala> list(0) = 10
<console>:9: error: value update is not a member of List[Int]
              list(0) = 10
              ^

默認的List是在:

scala> List
res59: scala.collection.immutable.List.type = scala.collection.immutable.List$@3e98fd35

所以不能修改,但是嘗試導入可修改的List也不能進行導入:

scala> import scala.collection.mutable.List
<console>:8: error: object List is not a member of package scala.collection.mutable
       import scala.collection.mutable.List

原因如下:

Scala 列表類似於數組,它們所有元素的類型都相同,但是它們也有所不同:
列表是不可變的,值一旦被定義了就不能改變,其次列表 具有遞歸的結構(也就是鏈接表結構)而數組不是。

List常用操作3

scala> val list = List(1, 2, 3, 4, 5, 6, 7)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7)

scala> list.take(5)
res60: List[Int] = List(1, 2, 3, 4, 5)

scala> list.takeWhile(_ <= 3)
res61: List[Int] = List(1, 2, 3)

scala> list.takeWhile(_ > 3)
res62: List[Int] = List()

scala> list.mkString
res63: String = 1234567

scala> list.count(_ % 2 == 0)
res64: Int = 3

scala> val fruit = "apples" :: ("oranges" :: ("pears" :: Nil))  // ::操作符從給定的頭和尾部創建一個新的列表
fruit: List[String] = List(apples, oranges, pears)

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

scala> val list2 = List(4, 5, 6)
list2: List[Int] = List(4, 5, 6)

scala> list1 ++ list2   // ++兩個集合之間的操作
res70: List[Int] = List(1, 2, 3, 4, 5, 6)

scala> list1.sum
res72: Int = 6

Set

1、數據集是不重復元素的集合。嘗試將已有元素加入進來是沒有效果的。比如

def setOps:Unit ={
    (Set(2,0,1) + 1).foreach(println(_))
}

2、Set不保留元素插入的順序。缺省情況下,集是以哈希集實現的,其元素根據hashCode方法的值進行組織。

Set(1,2,3,5,7,8).foreach(println(_))

3、鏈式哈希集可以記住元素被插入的順序。它會維護一個鏈表來達到這個目的。

val weeks= scala.collection.mutable.LinkedHashSet("Mo","Tu","We","Th","Fr")
weeks.foreach(println(_))

4、按照已排序的順序來訪問其中的元素

scala.collection.immutable.SortedSet(1,2,3,4,5,6).foreach(println(_))

set集合順序說明

直接看下面的測試代碼及註釋:

package cn.xpleaf.bigdata.p4.collection

import scala.collection.mutable.SortedSet

object _02CollectionOps {
  def main(args: Array[String]): Unit = {
    setOps1
  }

  /**
    * 關於scala集合順序的說明
    *     測試1:按照年齡進行升序,年齡相等,姓名降序
    *     測試2:要按照姓名升序比較,按照年齡升序比較
    * SortedSet在添加普通對象Person之類,報錯
    *   No implicit Ordering defined for Person
    *   要想在有序集合中添加元素,必須要讓元素具備比較性,要和給集合提供比較器
    *   在java中前者是要類實現Comparator,後者需要給集合提供一個比較器Comparator
    *   在scala中,前者需要讓類擴展Ordered的特質,後者給集合傳遞一個Ordering比較器
    *
    *   當兩個比較都實現的話,優先使用集合的比較器
    */
  def setOps1: Unit = {
    var set = SortedSet[Person]()(new Ordering[Person] {
      override def compare(x: Person, y: Person):Int = {
        var ret = x.getName.compareTo(y.getName)
        if(ret == 0) {
          ret = x.getAge.compareTo((y.getAge))
        }
        ret
      }
    })
    set.+= (new Person("王立鵬", 19))
    set.+= (new Person("馮 劍", 18))
    set.+= (new Person("劉銀鵬", 15))
    set.+= (new Person("李小小", 19))
    // println(set)
    set.foreach(println(_))
  }
}

class Person extends Ordered[Person] {
  private var name:String = _

  private var age:Int = _

  def this(name:String, age:Int) {
    this()
    this.name = name
    this.age = age
  }

  def getAge = age

  def getName = name

  override def toString: String = {
    s"[$name, $age]"
  }

  /**
    * 按照年齡進行升序,年齡相等,姓名降序
    * 升序:前面比後面
    * 降序:後面比前面
    */
  override def compare(that: Person) = {
    var ret = this.age.compareTo(that.age)
    if(ret == 0) {
      ret = that.name.compareTo(this.name)
    }
    ret
  }
}

輸出結果如下:

[馮 劍, 18]
[劉銀鵬, 15]
[李小小, 19]
[王立鵬, 19]

集合的函數式編程

1、集合的函數式編程非常之重要,這是我們以後工作中每天都在使用的編程方式。

2、必須完全掌握和理解Scala的高階函數是什麽意思,Scala的集合類的map、flatMap、reduce、reduceLeft、foreach等這些函數,就是高階函數,因為可以接收其他函數作為參數(部分高階函數可以參考前面整理的函數式編程筆記)

3、高階函數的使用,也是Scala與Java最大的一點不同!!!因為Java在1.8之前是沒有函數式編程的,也肯定沒有高階函數,也肯定無法直接將函數傳入一個方法,或者讓一個方法返回一個函數

4、對Scala高階函數的理解、掌握和使用,可以大大增強你的技術,而且也是Scala最有誘惑力、最有優勢的一個功能。

5、在Spark源碼中,有大量的函數式編程,所以必須掌握,才能看懂spark源碼。

  • foreach方法可以將某個函數應用到集合中的每個元素並產生結果的集合
scala> val names = List("Peter","Paul","Mary")
names: List[String] = List(Peter, Paul, Mary)

scala>  names.map(_.toUpperCase).foreach(println(_))
PETER
PAUL
MARY
  • Map函數每個後面都加上一個==》
scala> List("Peter","Paul","Mary").map(_ + "===>name").foreach(println(_))
Peter===>name
Paul===>name
Mary===>name
  • Flatmap按照空格進行劃分
scala> List("Peter Glad","Paul Hello","Mary Your").flatMap(_.split(" ")).foreach(println)
Peter
Glad
Paul
Hello
Mary
Your

Scala筆記整理(六):Scala集合庫