13 Collection 容器

  • 官方collection教程
  • 所有collection擴展自Iterable特質
  • 三大類,序列,集合,映射 seq set map
  • 對於幾乎所有的collection,都提供了可變和不可變的版本
  • 列表要麼是空的,要麼是一頭一尾,尾是列表
  • 集合沒有先後次序
  • + 將元素添加到無先後次序的容器中,+: 和 :+向前或向後追加到序列,++將兩個集合串接到一起,-和–移除元素(1個減號和兩個減號)
  • Iterable和Seq特質有數十個常見操作方法,很豐富
  • 映射、摺疊和拉鍊

主要的collection特質

  • 下面請欣賞一組圖片,注意藍底白字(特質trait)和黑底白字(類class),虛線(隱式轉換)和粗實線(默認實現)、細實線(通過類實現)圖片來源
  • 首先是scala.collection
    在這裏插入圖片描述
  • scala.collection.immutable
    在這裏插入圖片描述
  • scala.collection.mutable
    在這裏插入圖片描述
  • 圖例
    在這裏插入圖片描述
  • Iterable指的是那些能夠交出用來訪問集合中所有元素的Iterator的集合
val coll = List(2,1,4,3)  //任意Iterable特質的類
val iter = coll.iterator
while (iter.hasNext){println(iter.next())}
  • Seq是一個有先後次序的值的序列,例如數組或列表,IndexedSeq可以通過整型下標快速訪問任意元素,ArrayBuffer帶下標但鏈表不帶。
  • Set是一組沒有先後次序的值。
  • Map是一組鍵值的對偶。
  • 每一個collection特質或類都帶有一個apply方法的伴生對象,這個apply方法可以用來構建collection中的實例。
  • 上面的三個圖中出現的特質或類,統統可以直接拿來創建實例。圖中粗實線是默認實現的關係,不管是Seq還是Iterable,默認的都是List
scala> Seq(1,2,3)
res1: Seq[Int] = List(1, 2, 3)

scala> Iterable(1,2,3)
res2: Iterable[Int] = List(1, 2, 3)
  • 不同collection之間的轉換,可以調用toXX方法,和to[C]的泛型方法
scala> val list = List(1,2,3)
list: List[Int] = List(1, 2, 3)

scala> list.toVector
res5: Vector[Int] = Vector(1, 2, 3)

scala> list.to[Vector]
res6: Vector[Int] = Vector(1, 2, 3)
  • 使用==操作符實現任何seq、set、map的比較,如果不同類的collection比較,可以使用sameElements方法比較元素是否是相同。
scala> list == Vector(1,2,3)
res8: Boolean = true

scala> list == Set(1,2,3)
res9: Boolean = false

scala> list sameElements Set(1,2,3,2)
res10: Boolean = true

可變和不可變的collection

  • 不可變的collection可以安全共享引用,在多線程的應用程序中也無妨,scala.collection.Map, scala.collection.mutable.Map, scala.collection.immutable.Map,第一個是第二個和第三個的超類型
  • scala優先採用不可變集合,scala包和Predef對象裏還有指向不可變特質的類型別名List、Set、Map。
  • 使用可變的,import scala.collection.mutable,然後使用mutable.Map就是可變的了。

序列Seq

  • 不可變的Seq
    在這裏插入圖片描述
  • 可變的Seq
    在這裏插入圖片描述
  • 對比上面兩個圖可以看出,不可變版的默認實現是Vector,可變版本的默認實現是ArrayBuffer。
  • Vector支持快速隨機訪問,是以樹形結構的形式實現,每個節點可以有不超過32個子節點,速度很快
  • Range表示一個整數序列,只存儲開始值、結束值、增值,可以使用to和until方法構造Range對象
  • 此外還有棧、隊列、優先級隊列等
scala> Range(1,10)
res16: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> Range(1,10,2)
res17: scala.collection.immutable.Range = Range(1, 3, 5, 7, 9)

scala> 1 until 10
res18: scala.collection.immutable.Range = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> 1 to 10
res19: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
//棧
scala> val a =  collection.mutable.Stack(1,2,3)
a: scala.collection.mutable.Stack[Int] = Stack(1, 2, 3)
//入棧
scala> a.push(10)
res19: a.type = Stack(10, 1, 2, 3)
//出棧
scala> a.pop
res20: Int = 10

scala> a
res21: scala.collection.mutable.Stack[Int] = Stack(1, 2, 3)
//隊列
scala> val b =  collection.mutable.Queue(1,2,3,4)
b: scala.collection.mutable.Queue[Int] = Queue(1, 2, 3, 4)
//入隊
scala> b.enqueue(7)
//出隊
scala> b.dequeue
res23: Int = 1

列表

  • 列表只有頭和尾,head和tail,空列表Nil,head是第一個元素,tail是除了第一個元素以外的所有元素。
scala> val list = List(1,2,3,4)
list: List[Int] = List(1, 2, 3, 4)

scala> list.head
res24: Int = 1

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

scala> List(1).tail
res26: List[Int] = List()
  • 從給定的head和tail創建新列表 使用::操作符,這個操作符是右結合的,其右邊需要是個List
scala> 100::list
res28: List[Int] = List(100, 1, 2, 3, 4)
//下面的錯誤
scala> list :: 100
<console>:13: error: value :: is not a member of Int
       list :: 100
       
scala> list ::list
res30: List[Any] = List(List(1, 2, 3, 4), 1, 2, 3, 4)
//使用遞歸訪問列表,當然比較低效,下面的代碼就出現了java.lang.StackOverflowError
def sum(lst:List[Int]):Double={
  if (lst == Nil) 0 else (lst.head * 1.0) + sum(lst.tail)
}
val a = (1 to 100000).toList
//使用模式匹配計算,同樣的錯誤
def sum2(lst:List[Int]):Int=lst match{
  case Nil => 0
  case h :: t => h+sum2(t)
}
  • 可別版本的List使用ListBuffer,鏈表支撐的數據結構,高效地從任意一端添加或移除元素,但是添加或移除元素並不高效。

集 Set

  • Set是不重複的元素的collection,默認順序是hashcode方法進行組織,這樣查找元素比在數組或列表中更快
scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s+1
res34: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
  • 鏈式哈希set可以保留元素的插入順序LinkedHashSet
//多參數
scala> Set(1 to 5: _*)
res8: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)

scala> for(i <- Set(1,2,3,4,5,6)) println(i)
5
1
6
2
3
4

scala>  val s1 = collection.mutable.LinkedHashSet(1,2,3,4,5,6)
s1: scala.collection.mutable.LinkedHashSet[Int] = Set(1, 2, 3, 4, 5, 6)

scala> for(i <- s1) println(i)
1
2
3
4
5
6

  • 已排序集合 SortedSet
scala> collection.mutable.SortedSet(5,1,3,2,4)
res11: scala.collection.mutable.SortedSet[Int] = TreeSet(1, 2, 3, 4, 5)
  • 位組集合,BitSet,以一個字符序列的方式存放非負整數,只能是正的Int型的,不能太大,也不能是其他類型的。如果位組中有i,那麼低i個字位是1。
scala> collection.immutable.BitSet(1,2,3,2)
res35: scala.collection.immutable.BitSet = BitSet(1, 2, 3)

scala> collection.immutable.BitSet(1,2,2100000000)
java.lang.OutOfMemoryError: Java heap space
  • contains方法檢查一個集合是不是包含某個元素,subsetOf方法檢查某個集合是否被另一個集合包含
  • 集合的運算,交集、並集、差集,符號太麻煩,還是記憶union intersect diff簡單
操作 方法 符號1 符號2
union | ++
intersect &
diff &~ --
scala> val s1 = Set(1,2,3)
s1: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> val s2 = Set(2,3,4)
s2: scala.collection.immutable.Set[Int] = Set(2, 3, 4)

scala> val s3 = Set(7,8)
s3: scala.collection.immutable.Set[Int] = Set(7, 8)

scala> s1.union(s2)
res38: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 4)

scala> s1.intersect(s2)
res39: scala.collection.immutable.Set[Int] = Set(2, 3)

scala> s1.diff(s2)
res40: scala.collection.immutable.Set[Int] = Set(1)

scala> s3.intersect(s1)
res41: scala.collection.immutable.Set[Int] = Set()

添加或去除元素的操作符

  • 當你想添加或刪除某個元素或某些元素時,操作符取決於容器類型
  1. coll(k) , 即coll.apply(k)
    排在第k位的元素,或鍵k對應的映射值,適合Seq,Map
  2. coll :+ elem 或 elem +: coll,向後追加或向前追加了elem的與coll類型相同的容器,適合Seq。冒號靠近coll
scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)

scala> a :+ 4
res0: List[Int] = List(1, 2, 3, 4)

scala> 4 +: a
res1: List[Int] = List(4, 1, 2, 3)
  1. coll + elem 或 coll + (e1,e2,…)添加了給定元素的與coll相同的容器,適合Set Map
scala> val s = Set(1,2,3)
s: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> s + 5
res2: scala.collection.immutable.Set[Int] = Set(1, 2, 3, 5)

scala> s + (6,7)
res3: scala.collection.immutable.Set[Int] = Set(1, 6, 2, 7, 3)
  1. coll - elem 或 coll - (e1,e2,…)移除了給定元素的與coll相同的容器,適合Set Map ArrayBuffer
scala> s - 1
res4: scala.collection.immutable.Set[Int] = Set(2, 3)

scala> s - (2,3)
res5: scala.collection.immutable.Set[Int] = Set(1)
  1. coll ++ coll2或coll2 ++: coll,與coll類型相同的容器,同時包含兩個容器,適用於Iterable
scala> val r = 1 to 10
r: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val l = List(20,22)
l: List[Int] = List(20, 22)

scala> r ++ l
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 22)

scala> r ++: l
res8: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 22)

scala> s ++ r
res9: scala.collection.immutable.Set[Int] = Set(5, 10, 1, 6, 9, 2, 7, 3, 8, 4)

scala> r ++ s
res10: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3)

  1. coll --coll2,移除coll中的coll2,相當於diff,適用於Set Map ArrayBuffer
scala> s -- r
res15: scala.collection.immutable.Set[Int] = Set()
  1. elem :: lst,lst2 ::: lst,追加到lst中,適用於List ,帶冒號的是右結合的,左邊的元素添加都右邊
    三個冒號和 ++: 一樣,兩個冒號和 +: 一樣
scala> 1 :: List(3,4)
res19: List[Int] = List(1, 3, 4)

scala> List(1,2) :: List(3,4)
res20: List[Any] = List(List(1, 2), 3, 4)

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

scala> List(1,2) ++: List(3,4)
res22: List[Int] = List(1, 2, 3, 4)

scala> List(1,2) +: List(3,4)
res23: List[Any] = List(List(1, 2), 3, 4)

  1. set | set2 , set & set2 ,set &~ set2,並交差集,適用於Set
  2. coll += elem,coll += (e1,e2,…) ,coll ++= coll2 ,coll -= elem,coll -= (e1,e2,…) ,coll --= coll2,通過添加或移除元素修改coll,適用於可變的collection
scala> val s = collection.mutable.Set(1,2,3)
s: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

scala> s += 4
res24: s.type = Set(1, 2, 3, 4)

scala> s += (5,6,7)
res25: s.type = Set(1, 5, 2, 6, 3, 7, 4)

scala> s ++= Set(8,9)
res26: s.type = Set(9, 1, 5, 2, 6, 3, 7, 4, 8)

scala> s -= (1,2,3)
res27: s.type = Set(9, 5, 6, 7, 4, 8)

scala> s --= Set(9,10,11)
res28: s.type = Set(5, 6, 7, 4, 8)

  1. elem +=: coll,coll2 ++=:coll1,通過向前追加給定元素修改coll,適合ArrayBuffer
scala> val a = collection.mutable.ArrayBuffer(1,2)
a: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2)

scala> 4 +=: a
res30: a.type = ArrayBuffer(4, 1, 2)

scala> a += 5
res32: a.type = ArrayBuffer(4, 1, 2, 5)

scala> List(7,8) ++=: a
res33: a.type = ArrayBuffer(7, 8, 4, 1, 2, 5)

常用方法

介紹

在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

Iterable常用方法

  1. head,last,headOption,lastOption
scala> val a = List(1,2,3,4,5)
a: List[Int] = List(1, 2, 3, 4, 5)

scala> a.head
res0: Int = 1

scala> a.last
res1: Int = 5

scala> a.headOption
res2: Option[Int] = Some(1)

scala> a.lastOption
res3: Option[Int] = Some(5)
  1. tail,init
scala> a.tail
res4: List[Int] = List(2, 3, 4, 5)

scala> a.init
res5: List[Int] = List(1, 2, 3, 4)
//init 和 last,head和tail能夠拼接成完整的列表
scala> a.init :+ a.last
res8: List[Int] = List(1, 2, 3, 4, 5)

scala> a.head +: a.tail
res9: List[Int] = List(1, 2, 3, 4, 5)
  1. length,isEmpty
scala> a.length
res10: Int = 5

scala> a.isEmpty
res11: Boolean = false

scala> Nil.isEmpty
res12: Boolean = true
  1. map,flatMap,foreach,transform,collect
scala> val s = "I love China I love my homeland"
s: String = I love China I love my homeland

scala> val words = s.split(" ")
words: Array[String] = Array(I, love, China, I, love, my, homeland)

scala> words.map(_.toUpperCase)
res16: Array[String] = Array(I, LOVE, CHINA, I, LOVE, MY, HOMELAND)

scala> Array("I love China","I love my homeland","I love programming").map(_.split(" "))
res22: Array[Array[String]] = Array(Array(I, love, China), Array(I, love, my, homeland), Array(I, love, programming))

scala> Array("I love China","I love my homeland","I love programming").flatMap(_.split(" "))
res23: Array[String] = Array(I, love, China, I, love, my, homeland, I, love, programming)

scala> words.foreach(println)
I
love
China
I
love
my
homeland
// transform適用於可變的容器,直接修改本身,而不是生成新的
scala> collection.mutable.ArrayBuffer(1,2,3).transform(_*2)
res31: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(2, 4, 6)
//collect
scala> "+3-1".collect{case  '+' => 1; case '-' => -1}
 //scala.collection.immutable.IndexedSeq[Int] = Vector(1, -1)
scala> s.collect{case x if x.isUpper => 1;case y if y.isLower => -1; case _ => 0}
// scala.collection.immutable.IndexedSeq[Int] = Vector(1, 0, -1, -1, -1, -1, 0, 1, -1, -1, -1, -1, 0, 1, 0, -1, -1, -1, -1, 0, -1, -1, 0, -1, -1, -1,-1, -1, -1, -1, -1)
//collect的參數函數不一定需要對每個輸入都有定義
scala> s.collect{case x if x.isUpper => 1}
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 1, 1)
  1. reduceLeft.reduceRight,foldLeft,foldRIght
scala> a.map(_.toString).reduceLeft((x,y)=>(s"f(${x},${y})"))
res60: String = f(f(f(f(1,2),3),4),5)

scala> a.map(_.toString).reduceRight((x,y)=>(s"f(${x},${y})"))
res61: String = f(1,f(2,f(3,f(4,5))))

scala> a.map(_.toString).foldLeft("0")((x,y)=>(s"f(${x},${y})"))
res65: String = f(f(f(f(f(0,1),2),3),4),5)

scala> a.map(_.toString).foldRight("0")((x,y)=>(s"f(${x},${y})"))
res67: String = f(1,f(2,f(3,f(4,f(5,0)))))
  1. reduce,fold,aggregate
    (Since version 2.13.0) aggregate is not relevant for sequential collections. Use foldLeft(z)(seqop) instead.
scala> a.map(_.toString).reduce((x,y)=>(s"f(${x},${y})"))
res71: String = f(f(f(f(1,2),3),4),5)

scala> a.map(_.toString).fold("0")((x,y)=>(s"f(${x},${y})"))
res72: String = f(f(f(f(f(0,1),2),3),4),5)

scala> val c = Array("1","2","3","4","5","6")
c: Array[String] = Array(1, 2, 3, 4, 5, 6)
//aggregate較難理解,針對並行的collection
scala> c.par.aggregate("0")(
     |       {(x:String,y:String)=>s"f(${x},${y})"},
     |       {(a:String,b:String)=>s"g(${a},${b})"}
     |     )
res74: String = g(g(f(0,1),g(f(0,2),f(0,3))),g(f(0,4),g(f(0,5),f(0,6))))


  1. sum product max min
scala> a.sum
res79: Int = 15

scala> a.product
res80: Int = 120

scala> a.min
res81: Int = 1

scala> a.max
res82: Int = 5

scala> (1 to 100) .product
res84: Int = 0


  1. count forall,exists
scala> a.count( _ > 2)
res2: Int = 3

scala> a.forall( _ > 2)
res3: Boolean = false

scala> a.forall( _ > 0)
res4: Boolean = true

scala> a.exists( _ > 0)
res5: Boolean = true

scala> a.exists( _ < 0)
res6: Boolean = false

  1. filter , filterNot , partition
scala> a.filter( _ > 2 )
res7: List[Int] = List(3, 4, 5)

scala> a.filter( _ > 10 )
res8: List[Int] = List()

scala> a.filterNot( _ > 10 )
res9: List[Int] = List(1, 2, 3, 4, 5)

scala> a.partition( _ > 10 )
res10: (List[Int], List[Int]) = (List(),List(1, 2, 3, 4, 5))

scala> a.partition( _ > 2 )
res11: (List[Int], List[Int]) = (List(3, 4, 5),List(1, 2))
  1. takeWhile(pred), dropWhile (pred), span (pred)
scala> val b = List(3,1,2,9,1,8,2)
b: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.takeWhile(_ > 3)
res12: List[Int] = List()

scala> b.dropWhile(_ > 3)
res13: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.span(_ > 3)
res14: (List[Int], List[Int]) = (List(),List(3, 1, 2, 9, 1, 8, 2))

scala> b.takeWhile(_ < 4)
res15: List[Int] = List(3, 1, 2)

scala> b.span(_ < 4)
res16: (List[Int], List[Int]) = (List(3, 1, 2),List(9, 1, 8, 2))

  1. take drop splitAt
scala> b
res17: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.take(3)
res18: List[Int] = List(3, 1, 2)

scala> b.drop(3)
res19: List[Int] = List(9, 1, 8, 2)

scala> b.splitAt(3)
res20: (List[Int], List[Int]) = (List(3, 1, 2),List(9, 1, 8, 2))
  1. takeRight,dropRIght
scala> b.takeRight(3)
res0: List[Int] = List(1, 8, 2)

scala> b.dropRight(3)
res1: List[Int] = List(3, 1, 2, 9)
  1. slice,view
scala> b.slice(2,4)
res2: List[Int] = List(2, 9)

scala> b.view(2,4)
res5: scala.collection.SeqView[Int,List[Int]] = SeqViewS(...)
//調用view的force方法求值
scala> b.view(2,4).force
res6: List[Int] = List(2, 9)


  1. zip,zipAll,zipWithIndex
scala> val prices = List(5.0,20.0,9.95)
prices: List[Double] = List(5.0, 20.0, 9.95)

scala> val quantities = List(10,2,1)
quantities: List[Int] = List(10, 2, 1)
//zip後的每個元素是個二元組
scala> prices.zip(quantities)
res7: List[(Double, Int)] = List((5.0,10), (20.0,2), (9.95,1))
//如果一個比較短,則以短的爲主
scala> prices.zip(List(5,20))
res8: List[(Double, Int)] = List((5.0,5), (20.0,20))
scala> prices.zip(Nil)
res10: List[(Double, Nothing)] = List()
//zipAll可以指定默認值,如果下例中,0是prices的默認值,1是參數列表的默認值
scala> prices.zipAll(List(5,20),0,1)
res12: List[(AnyVal, Int)] = List((5.0,5), (20.0,20), (9.95,1))

scala> prices.zipAll(List(5,20,21,22,23),0,1)
res13: List[(AnyVal, Int)] = List((5.0,5), (20.0,20), (9.95,21), (0,22), (0,23))
//zipWIthIndex結果的第二個元素是第一個元素的下標索引
scala> prices.zipWithIndex
res14: List[(Double, Int)] = List((5.0,0), (20.0,1), (9.95,2))
  1. grouped(n),sliding(n)返回長度爲n的子集合迭代器,
scala> b
res16: List[Int] = List(3, 1, 2, 9, 1, 8, 2)
//滑動窗口步長爲n,窗口大小爲n
scala> b.grouped(3).toList
res18: List[List[Int]] = List(List(3, 1, 2), List(9, 1, 8), List(2))
//滑動窗口,步長爲1,窗口大小爲n
scala> b.sliding(3).toList
res19: List[List[Int]] = List(List(3, 1, 2), List(1, 2, 9), List(2, 9, 1), List(9, 1, 8), List(1, 8, 2))
  1. groupBy(function),返回一個映射,對於每一個x,由y=function(x),鍵是所有的y,值是y對應的所有的x
scala> b
res23: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.groupBy(_*3)
res24: scala.collection.immutable.Map[Int,List[Int]] = Map(24 -> List(8), 6 -> List(2, 2), 9 -> List(3), 27 -> List(9), 3 -> List(1, 1))
  1. mkString,addString
//mkString接受一個或三個參數
scala> b.mkString("-")
res25: String = 3-1-2-9-1-8-2

scala> b.mkString("!","-","?")
res26: String = !3-1-2-9-1-8-2?
//addString將字符串添加到StringBuilder中,字符串構建器
//返回的是修改後的StringBuilder
scala> val sb = new StringBuilder
sb: StringBuilder =

scala> b.addString(sb,"-")
res29: StringBuilder = 3-1-2-9-1-8-2

scala> b.addString(sb,"!","-","?")
res30: StringBuilder = 3-1-2-9-1-8-2!3-1-2-9-1-8-2?
  1. toIterable,to[C]轉換爲其他類型的collection
scala> b.to
to        toBuffer       toIterable   toList   toParArray   toSet      toString        toVector
toArray   toIndexedSeq   toIterator   toMap    toSeq        toStream   toTraversable

Seq常用方法

  1. contains,containsSlice,startsWith,endsWith,第一個的參數爲元素,其他的參數爲Seq
scala> b
res32: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.contains(9)
res33: Boolean = true

scala> b.containsSlice(Array(2,9))
res34: Boolean = true

scala> b.containsSlice(Array(2,9,2))
res35: Boolean = false

scala> b.startsWith(Array(3))
res37: Boolean = true

scala> b.startsWith(Array(2))
res38: Boolean = false

scala> b.startsWith(Array(3,1,2))
res39: Boolean = true

scala> b.endsWith(Array(2))
res40: Boolean = true
  1. indexOf,lastIndexOf,indexOfSlice,lastIndexOfSlice
    第一個或最後一個的索引
scala> b
res41: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.indexOf(1)
res42: Int = 1

scala> b.lastIndexOf(1)
res43: Int = 4

scala> b.indexOfSlice(Array(1,2,9))
res44: Int = 1

scala> b.lastIndexOfSlice(Array(2))
res45: Int = 6

  1. indexWhere滿足條件的首個元素的下標
scala> b.indexWhere(_>7)
res47: Int = 3

  1. prefixLength,segmentLength,第一個滿足條件的最長元素序列的長度,
    segmentLength可以指定從第幾個元素開始查找。
scala> b
res50: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.prefixLength(_ < 8)
res51: Int = 3
scala> b
res52: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.segmentLength(_ < 8 , 3)
res53: Int = 0

scala> b.segmentLength(_ < 8 , 2)
res54: Int = 1

scala> b.segmentLength(_ < 8 , 1)
res55: Int = 2

  1. padTo(n,fill),拷貝當前seq到一個新的,長度爲n,如果原來的長度不夠就用fill填充,如果原長度更大就返回原Seq的拷貝
scala> b.padTo(20,5)
res57: List[Int] = List(3, 1, 2, 9, 1, 8, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5)
scala> b.padTo(4,5)
res59: List[Int] = List(3, 1, 2, 9, 1, 8, 2)
  1. intersect,diff,類似Set的交集、差集,不過只對第一次滿足條件的操作
scala> b
res65: List[Int] = List(3, 1, 2, 9, 1, 8, 2)

scala> b.intersect(Array(1,2,5))
res66: List[Int] = List(1, 2)

scala> b.diff(Array(1,2,5))
res67: List[Int] = List(3, 9, 1, 8, 2)

scala> b.union(Array(1,2,5))
res68: List[Int] = List(3, 1, 2, 9, 1, 8, 2, 1, 2, 5)
  1. reverse
scala> b.reverse
res69: List[Int] = List(2, 8, 1, 9, 2, 1, 3)
  1. sorted,sortWith,sortBy
scala> b.sorted
res72: List[Int] = List(1, 1, 2, 2, 3, 8, 9)

scala> b.sortWith(_>_)
res75: List[Int] = List(9, 8, 3, 2, 2, 1, 1)

9.permutations,combinations(n)返回所有排列組合的迭代器,n爲指定子序列的長度

scala> List(1,2,3).permutations.toList
res78: List[List[Int]] = List(List(1, 2, 3), List(1, 3, 2), List(2, 1, 3), List(2, 3, 1), List(3, 1, 2), List(3, 2, 1))
scala> List(1,2,1).permutations.toList
res79: List[List[Int]] = List(List(1, 1, 2), List(1, 2, 1), List(2, 1, 1))

scala> List(1,2,3).combinations(2).toList
res81: List[List[Int]] = List(List(1, 2), List(1, 3), List(2, 3))

  • 流stream是一個尾部被懶計算的不可變列表,也就是說只有當你需要時才被計算
  • 流會緩存訪問過的行
  • 不要直接使用.force,應該先用take再用force
scala> def numsFrom(n:BigInt):Stream[BigInt] = n #:: numsFrom(n+1)
numsFrom: (n: BigInt)Stream[BigInt]
//得到的是流對象
scala> val tenOrMore = numsFrom(10)
tenOrMore: Stream[BigInt] = Stream(10, ?)
scala> tenOrMore.tail.tail.tail
res3: scala.collection.immutable.Stream[BigInt] = Stream(13, ?)
scala> tenOrMore.take(5).force
res4: scala.collection.immutable.Stream[BigInt] = Stream(10, 11, 12, 13, 14)
//不要直接使用.force,應該先用take再用force


scala> import  scala.io.Source
import scala.io.Source

scala> val words = Source.fromFile("D:\\data\\shuihu.txt").getLines.toStream
words: scala.collection.immutable.Stream[String] = Stream(1     天魁星  呼保義  宋江, ?)

scala> words(5)
res0: String = 6        天雄星  豹子頭  林沖

scala> words.take(5).force
res1: scala.collection.immutable.Stream[String] = Stream(1      天魁星  呼保義  宋江, 2 天罡星  玉麒麟  盧俊義, 3               天機星  智多星  吳用, 4 天閒星  入雲龍  公孫勝, 5       天勇星  大刀    關勝)

scala> s.mkString("\n")
res3: String =
1       天魁星  呼保義  宋江
2       天罡星  玉麒麟  盧俊義
3       天機星  智多星  吳用
4       天閒星  入雲龍  公孫勝
5       天勇星  大刀    關勝

懶視圖 lazy view

  • 使用view方法得到懶視圖
  • force方法可以強制求值,但是不要直接使用流的force方法
  • 跟流不同,視圖不會緩存任何值,再次調用時會從頭開始計算
scala> val palindromicSquares =(1 to 100000).view.map(x=>x*x).filter(x=> x.toString == x.toString.reverse )
palindromicSquares: scala.collection.SeqView[Int,Seq[_]] = SeqViewMF(...)
//執行如下代碼會執行得到十個
scala> palindromicSquares.take(10).mkString(",")
res4: String = 1,4,9,121,484,676,10201,12321,14641,40804
  • 調用apply方法會強制對整個視圖求值
//不要這樣調用
scala> palindromicSquares(20)
res7: Int = 102030201
//使用下面的方法
scala> palindromicSquares.take(20).last
res9: Int = 100020001

並行collection

  • 很方便的併發執行,例如 coll.par.sum
  • par方法產生當前集合的一個並行實現,會儘可能並行地執行集合方法
  • 可以發現使用了所有核的CPU進行了計算
scala> (1 to 1000000000).par.sum

在這裏插入圖片描述

  • 使用for循環遍歷par後的,可以看到順序是按照作用於該任務的線程產出的順序輸出的。
  • 而如果使用for/yield循環,可以看到介個是依次組裝的
scala> for (i <- (1 to 24).par) print(s"${i} ")
1 2 3 19 5 10 11 7 16 18 20 21 17 8 9 12 24 4 23 13 22 6 15 14

scala> for (i <- (1 to 24).par) yield(s"${i} ")
res16: scala.collection.parallel.immutable.ParSeq[String] = ParVector("1 ", "2 ", "3 ", "4 ", "5 ", "6 ", "7 ", "8 ", "9 ", "10 ", "11 ", "12 ", "13 ", "14 ", "15 ", "16 ", "17 ", "18 ", "19 ", "20 ", "21 ", "22 ", "23 ", "24 ")

scala> (for (i <- (1 to 1000).par) yield i) == (1 to 1000)
res18: Boolean = true
  • 如果並行運算修改了共享的變量,結果無法預知,不要更新一個共享計數器,如果非要這樣做,結果不是預期的結果了。
scala> var count = 0
count: Int = 0

scala> for (i <- (1 to 24).par)  count += 1
//看起來沒問題
scala> count
res20: Int = 24

//如果數再大點
scala> var count = 0
count: Int = 0

scala> for (i <- (1 to 24000).par)  count += 1

scala> count
res25: Int = 4946
//再試一次,結果又變了
scala> var count = 0
count: Int = 0

scala> for (i <- (1 to 24000).par)  count += 1

scala> count
res27: Int = 6742
  • 使用seq方法將並行collection轉爲順序的
val result = (1 to 100).par.map(_+1).seq
  • 不是所有的方法都能被並行化
  • 默認情況下,並行集合使用全局的fork-join線程池,適用於高處理器開銷的計算,如果執行的步驟包含阻塞調用,應該選用執行上下文(execution context),第17章
發佈了75 篇原創文章 · 獲贊 83 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章