4. 映射和元组

4.1 构造映射
  • 可以这样构造一个映射:val scores = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
  • 这样构造出来的Map是不可变的,如果需要一个可变的映射,可以使用:val scores = scala.collection.mutable.Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
  • 如果想构造一个空的映射,则需要指定参数类型:val scores = new scala.collection.mutable.HashMap[String, Int]
  • 事实上,"Alice" -> 10操作符等同于`("Alice", 10),但前者显然看起来更加直观,更加的Scala。
4.2 获取映射中的值
  • 获取映射的时候,使用圆括号:val bobScore = scores("Bob")
  • 但有时候判断映射中是否有指定的键,使用contains方法:val bobScore = if (scores.contains("Bob")) scores("Bob") else 0
  • 其实,还有更Scala的写法:val bobScore = scores.getOrElse("Bob", 0)
  • 注意,映射的get方法返回的是Option对象,在14章中会详细介绍。
4.3 更新映射中的值
  • 只有可变的映射可以进行值的更新。scores("Bob") = 10
  • 或者可以使用+=操作符来添加多个关系:scores += ("Bob" -> 10, "Fred" -> 7)
  • 要移除某个键和对应的值,使用-=操作符:scores -= "Alice"
  • 上述的+=-=操作符都是针对可变映射而言的,对于不可变的映射,可以新建一个映射:val newScores = score + ("Bob" -> 10, "Fred" -> 7)
  • 或者使用var来声明集合:
    var scores = ...
    scores = scores + ("Bob" -> 10, "Fred" -> 7)
    scores = scores - "Alice"
    

实际上,这样不停的创建新映射的效率并不会很低,老的映射与新的映射共享大部分结构。

4.4 迭代映射
  • 可以通过for ((k, v) <- 映射)来遍历映射。
  • 如果只需要访问键或值,可以使用scores.keySetscores.values
  • 反转映射的快速方法:for ((k, v) <- 映射) yield (v, k)
4.5 已排序映射
  • Scala的映射实现方式有2种---哈希表与平衡树,默认是哈希表。Scala没有可变的树形映射,如果需要按一定顺序访问所有的键,可以使用SortedMap
  • val scores = scala.collection.immutable.SortedMap("Alice" -> 10, "Fred" -> 7, "Bob" -> 3, "Cindy" -> 8)
  • 如果你需要可变的树形映射,建议使用Java的TreeMap
  • 如果想要按照插入顺序来访问所有键,使用LinkedHashMap
  • val scores = scala.collection.immutable.LinkedHashMap("January" -> 1, "February" -> 2, "March" -> 3, ...)
4.6 与Java的互操作

通过隐式转换,可以实现Java与Scala的映射转换。

Java转Scala映射:

import scala.collection.JavaConversions.mapAsScalaMap
val scores: scala.collection.mutable.Map[String, Int] = new util.TreeMap[String, Int]()

Scala转Java映射:

import scala.collection.JavaConversions.mapAsJavaMap
import java.awt.font.TextAttribute._
val attrs = Map(FAMILY -> "Serif", SIZE -> 12)
val font = new Font(attrs)
4.7 元组
  • 元组是不同类型集的聚集,如:(1, 3.14, "Fred")是一个类型为Tuple3[Int, Double, java.lang.String]的元组。
  • 通过_1_2_3访问元组的组元(注意组元从1开始索引,而不是0)。
  • 可以使用模式匹配来获取元组的组员,如果有不需要的成员,用_来代替。
  • val (first, second, _) = t
  • 元组可以用于函数需要返回值不止一个的情况。
4.8 拉链操作

元组可以把多个值绑在一起,通常可以用zip方法来完成,举例来说:

val symbols = Array("<", "-", ">")
val counts = Array(2, 10, 2)
val pairs = symbols.zip(counts)

返回的结果是Array(("", 2))

toMap方法可以将对偶(二元组)的集合转换成映射:keys.zip(values).toMap