Chap 13 集合 Collections

focus on

  1. 所有的 Collection 都扩展自 Iterable 特质(trait)

  2. Collection 分三大类, 分别为 Seq、Set、Map

  3. Collection Class,Scala 都提供 mutable 和 imutable 的版本

  4. Scala 列表要么是Empty, 要么 拥有 a head a tail, 其中 tail 本身又是一个 列表

  5. 集 是无 先后次序 的集合

  6. 用 LinkedHashSet 来保留插入顺序, 或者用 SortedSet 来按顺序进行迭代

  7. +将元素添加到 无先后次序 的 集合 中; +:,:+向前后追加到序列; ++将两个集合串接; -,-- 移除元素

  8. Iterable 和 Seq 特质trait 有数十个用于常见操作的方法

  9. 映射、折叠、拉链 是有用的技巧,用来将 函数 或 操作 应用到 collection 中的 element

13.1 主要的 Collection trait

Collections-trait

继承层级 和 Java 很相似, 同时有一些不错的改进:

  1. 映射 隶属于 同一个继承层级 而不是一个单独的层级关系

  2. IndexedSeq 是 array 的超类型, 但不是 list 的超类型

Java, AyyayList 和 LinkedList 实现同一个 List 接口, 随机访问效率代码困难。 RandomAccess 这个标记接口来应对这个缺陷

Scala 统一访问原则

  1. Iterable(0xFF, 0xFF00, 0xFF0000)

  2. Set(Color.RED, Color.GREEN, Color.BLUE)

  3. Map(Color.RED -> 0xFF0000, Color.GREEN -> 0xFF00, Color.BLUE -> 0xFF)

  4. SortedSet("Hello", "World")

13.2 immutable、mutable

scala.collection.immutable

immutable

scala.collection.mutable

mutable

13.3 Seq

不可变 seq可变 seq

seq-pic

不可变序列 : 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)
  }
}

blair
209 声望31 粉丝

我是 Blair


引用和评论

0 条评论