Chap 13 集合 Collections
focus on
所有的 Collection 都扩展自 Iterable 特质(trait)
Collection 分三大类, 分别为 Seq、Set、Map
Collection Class,Scala 都提供 mutable 和 imutable 的版本
Scala 列表要么是Empty, 要么 拥有 a head a tail, 其中 tail 本身又是一个 列表
集 是无 先后次序 的集合
用 LinkedHashSet 来保留插入顺序, 或者用 SortedSet 来按顺序进行迭代
+将元素添加到 无先后次序 的 集合 中; +:,:+向前后追加到序列; ++将两个集合串接; -,-- 移除元素
Iterable 和 Seq 特质trait 有数十个用于常见操作的方法
映射、折叠、拉链 是有用的技巧,用来将 函数 或 操作 应用到 collection 中的 element
13.1 主要的 Collection trait
继承层级 和 Java 很相似, 同时有一些不错的改进:
映射 隶属于 同一个继承层级 而不是一个单独的层级关系
IndexedSeq 是 array 的超类型, 但不是 list 的超类型
Java, AyyayList 和 LinkedList 实现同一个 List 接口, 随机访问效率代码困难。 RandomAccess 这个标记接口来应对这个缺陷
Scala 统一访问原则
Iterable(0xFF, 0xFF00, 0xFF0000)
Set(Color.RED, Color.GREEN, Color.BLUE)
Map(Color.RED -> 0xFF0000, Color.GREEN -> 0xFF00, Color.BLUE -> 0xFF)
SortedSet("Hello", "World")
13.2 immutable、mutable
scala.collection.immutable
scala.collection.mutable
13.3 Seq
不可变 seq 与 可变 seq
不可变序列 : Range、Vector、List、Stream、Stack、Queue
可变序列 : ArrayBuffer、Priority Queue、LinkedList、Double LinkedList、Stack、Queue
Range 表示一个整数序列。 (begin、end、increment). (to,until 可构造 range)
Vector 是 ArrayBuffer 的不可变版本。
13.4 List
object ListTest extends App {
val digits = List(4, 2)
println(digits.head)
println(digits.tail)
println(digits.tail.head)
println(digits.tail.tail) // List() is Nil
println((9 :: 4 :: 2 :: Nil).sum) // :: 右结合性, 9 :: (4 :: (2 :: Nil))
// 链表求sum,你可以使用 递归 或者 模式匹配 case Nil => 0;case h :: t => h + sum(t)
}
13.5 LinkedList
object LinkedListTest {
def main(args: Array[String]) {
val lst = scala.collection.mutable.LinkedList(1, -2, 7, -9)
var cur = lst
while (cur != Nil) {
if (cur.elem < 0) {
cur.elem = 0
}
cur = cur.next
}
println(lst) // LinkedList(1, 0, 7, 0)
println(cur) // LinkedList()
}
}
注意 : 如果你想将列表中的某个节点变成列表中的最后一个节点, 你不能将 next 引用设为 Nil, 而应该将它设为 LinkedList.empty. 也不要将它设成 null, 不然你在遍历该链表时会遇到 空指针 错误
13.6 Set
Set 是不重复 elem 的 Collection。 缺省情况下,Set 是以 hash集 实现的。
(Scala 和 Java 一样, 每个对象都有 hashCode 方法)
图片
(bit set) 是 Set 的一种实现。
13.7 操作符、常用方法
操作符
操作符 | 描述 | 集合类型 |
---|---|---|
coll :+ elem elem +: coll |
追加到尾部或头部的与coll类型相同的集合 | Seq |
... | ... | ... |
一般, + 用于将 elem 添加到 无 先后次序的集合, 而 +: 和 :+ 则是将元素添加到有先后次序的集合的开头和末尾
常用方法
Iterable Trait 方法
方法 | 描述 | |
---|---|---|
head、last、headOption、lastOption | 返回第一个元素, ... | |
... | ... |
Seq Trait 方法
方法 | 描述 | |
---|---|---|
contains(elem), ... | 返回true,如包含。 ... | |
... | ... |
13.8 将函数映射到Collection
想要对 Collection 中所有 element 进行变换。 map 方法 可以将某个函数应用到集合中的每个元素并产出其结果的集合。
object MapTest {
def main(args: Array[String]) {
val names = List("Peter", "Paul", "Mary")
names.map(_.toUpperCase) // for (n <- names) yield n.toUpperCase
// flatMap, 将所有的值串接在一起
println(names.map(ulcase))
println(names.flatMap(ulcase))
// collect 方法用于 偏函数 (partial function) -- 那些并没有对所有可能的输入值进行定义的函数. 它产出被定义的所有参数的函数值的集合.
"-3+4".collect { case '+' => 1; case '-' => -1 } // Vector(-1, 1)
// 应用函数 到 各个元素 仅仅是为了 它的副作用而不关心函数值的话,可以用 foreach
names.foreach(println)
}
def ulcase(s: String) = Vector(s.toUpperCase, s.toLowerCase)
}
13.9 拉链操作
object ZipTest extends App {
val prices = List(5.0, 20.0, 9.95)
val quantities = List(10, 2, 1)
val zipres = prices zip quantities
zipres.foreach(println)
(zipres map { p => p._1 * p._2 }) sum
// 如果一个 集合 比 另一个短,那么集合的元素数量是短的那个
// zipAll 方法, 让你指定较短列表的缺省值. 如下是 : 1
println("zipAll : ")
List(5.0, 20.0, 9.95).zipAll(List(10), 2.0, 1).foreach(println)
// zipWithIndex 方法返回对偶的列表
println("zipWithIndex : ")
println("Scala".zipWithIndex.max)
println("Scala".zipWithIndex.max._2)
}
// Output
(5.0,10)
(20.0,2)
(9.95,1)
zipAll :
(5.0,10)
(20.0,1)
(9.95,1)
zipWithIndex :
(l,3)
3
Process finished with exit code 0
13.10 迭代器
你可以用 iterator 方法 从集合获得 一个 迭代器。
object LazyTest {
def main(args: Array[String]) {
// lazy 视图
val powers = (0 until 1000).view.map(pow(10, _))
println(powers)
println(powers(100)) // 10^100 被计算,其他值没有被计算
println("\nlazy collection : ")
// lazy collection
// 先执行前面map, 产生中间集合, 再执行后面的 map
(0 to 5).map(pow(10, _)).map(1 / _).foreach(println)
println("\nlazy view : ")
// lazy view
// 产出的是记住两个 map 操作的view.
// 当求值动作被强制执行时, 对于每个元素, 这两个操作被同时执行, 不需要额外构建中间集合
(0 to 5).view.map(pow(10, _)).map(1 / _).force.foreach(println)
// 当然,你也可以这样,对于这个简单的例子来说
(0 to 5).map(x => pow(10, -x))
println("\n0 to 5 : ")
(0 to 5).foreach(println)
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。