一个 Map 是一个 Iterable,它由键值对组成(也称为映射或关联)。Scala 的 Predef 对象提供了一个隐式转换,允许您将 key -> value 作为 (key, value) 对的替代语法。例如 Map("x" -> 24, "y" -> 25, "z" -> 26) 与 Map(("x", 24), ("y", 25), ("z", 26)) 的含义完全相同,但可读性更好。
地图上的基本操作类似于集合上的操作。它们在以下表格中总结,并分为以下类别
- 查找 操作
apply、get、getOrElse、contains和isDefinedAt。这些操作将映射转换为从键到值的偏函数。映射的基本查找方法是:def get(key): Option[Value]。操作m.get(key)测试映射是否包含给定key的关联。如果是,则返回Some中的关联值。如果映射中未定义任何键,则get返回None。映射还定义了一个apply方法,该方法直接返回与给定键关联的值,而不会将其包装在Option中。如果映射中未定义键,则会引发异常。 - 添加和更新
+、++、updated,这些操作允许您向映射添加新的绑定或更改现有的绑定。 - 删除
-、--,这些操作从映射中删除绑定。 - 子集合生成器
keys、keySet、keysIterator、values、valuesIterator,这些操作以各种形式分别返回映射的键和值。 - 转换
filterKeys和mapValues,这些操作通过过滤和转换现有映射的绑定来生成新的映射。
Map 类中的操作
| 是什么 | 它做什么 |
|---|---|
| 查找 | |
ms.get(k) |
映射 ms 中与键 k 关联的值,作为选项,如果未找到则为 None。 |
ms(k) |
(或写成 ms.apply(k))映射 ms 中与键 k 关联的值,如果未找到则抛出异常。 |
ms.getOrElse(k, d) |
映射 ms 中与键 k 关联的值,如果未找到则返回默认值 d。 |
ms.contains(k) |
测试 ms 是否包含键 k 的映射。 |
ms.isDefinedAt(k) |
与 contains 相同。 |
| 子集合 | |
ms.keys |
包含 ms 中每个键的可迭代对象。 |
ms.keySet |
包含 ms 中每个键的集合。 |
ms.keysIterator |
生成 ms 中每个键的迭代器。 |
ms.values |
包含 ms 中每个键关联的值的可迭代对象。 |
ms.valuesIterator |
生成 ms 中每个键关联的值的迭代器。 |
| 转换 | |
ms.view.filterKeys(p) |
一个映射视图,只包含 ms 中键满足谓词 p 的映射。 |
ms.view.mapValues(f) |
一个映射视图,通过将函数 f 应用于 ms 中每个键关联的值而生成。 |
不可变映射除了支持添加和删除映射的操作外,还会返回新的 Map,如下表所示。
不可变类 immutable.Map 中的操作
| 是什么 | 它做什么 |
|---|---|
| 添加和更新 | |
ms.updated(k, v)或 ms + (k -> v) |
包含 ms 中所有映射以及从键 k 到值 v 的映射 k -> v 的映射。 |
| 移除 | |
ms.remove(k)或 ms - k |
包含所有 ms 映射的映射,但排除键 k 的任何映射。 |
ms.removeAll(ks)或 ms -- ks |
包含所有 ms 映射的映射,但排除任何键在 ks 中的映射。 |
可变映射除了以下表格中总结的操作外,还支持其他操作。
mutable.Map 类中的操作
| 是什么 | 它做什么 |
|---|---|
| 添加和更新 | |
ms(k) = v |
(或者,写出来,ms.update(k, v))。将键 k 到值 v 的映射添加到映射 ms 中,作为副作用,覆盖任何先前对 k 的映射。 |
ms.addOne(k -> v)或 ms += (k -> v) |
将键 k 到值 v 的映射添加到映射 ms 中,作为副作用,并返回 ms 本身。 |
ms.addAll(xvs)或 ms ++= kvs |
将 kvs 中的所有映射添加到 ms 中,作为副作用,并返回 ms 本身。 |
ms.put(k, v) |
将键 k 到值 v 的映射添加到 ms 中,并返回先前与 k 关联的任何值,作为选项。 |
ms.getOrElseUpdate(k, d) |
如果键 k 在映射 ms 中定义,则返回其关联的值。否则,使用映射 k -> d 更新 ms 并返回 d。 |
| 移除 | |
ms.subtractOne(k)或 ms -= k |
从 ms 中删除具有键 k 的映射,作为副作用,并返回 ms 本身。 |
ms.subtractAll(ks)或 ms --= ks |
从 ms 中删除 ks 中的所有键,作为副作用,并返回 ms 本身。 |
ms.remove(k) |
从 ms 中删除任何具有键 k 的映射,并返回先前与 k 关联的任何值,作为选项。 |
ms.filterInPlace(p) |
仅保留 ms 中具有满足谓词 p 的键的映射。 |
ms.clear() |
从 ms 中移除所有映射。 |
| 转换 | |
ms.mapValuesInPlace(f) |
使用函数 f 转换映射 ms 中的所有关联值。 |
| 克隆 | |
ms.clone |
返回一个新的可变映射,其映射与 ms 相同。 |
映射的添加和删除操作与集合的添加和删除操作类似。可变映射 m 通常在原地更新,使用两种变体 m(key) = value 或 m += (key -> value)。还有一种变体 m.put(key, value),它返回一个 Option 值,该值包含先前与 key 关联的值,或者如果 key 在映射中不存在,则返回 None。
getOrElseUpdate 对用作缓存的映射很有用。假设您有一个通过调用函数 f 触发的昂贵计算。
scala> def f(x: String): String = {
println("taking my time."); Thread.sleep(100)
x.reverse
}
f: (x: String)String
scala> def f(x: String): String =
println("taking my time."); Thread.sleep(100)
x.reverse
def f(x: String): String
进一步假设 f 没有副作用,因此用相同的参数再次调用它将始终产生相同的结果。在这种情况下,您可以通过将参数和 f 结果的先前计算绑定存储在映射中,并且仅在映射中未找到参数的结果时才计算 f 的结果,从而节省时间。可以说,该映射是函数 f 计算的缓存。
scala> val cache = collection.mutable.Map[String, String]()
cache: scala.collection.mutable.Map[String,String] = Map()
您现在可以创建 f 函数的更高效的缓存版本。
scala> def cachedF(s: String): String = cache.getOrElseUpdate(s, f(s))
cachedF: (s: String)String
scala> cachedF("abc")
taking my time.
res3: String = cba
scala> cachedF("abc")
res4: String = cba
请注意,getOrElseUpdate 的第二个参数是按名称传递的,因此上面的 f("abc") 的计算仅在 getOrElseUpdate 需要其第二个参数的值时执行,这正是当其第一个参数在 cache 映射中找不到时。您也可以使用基本映射操作直接实现 cachedF,但这需要更多代码。
def cachedF(arg: String): String = cache.get(arg) match {
case Some(result) => result
case None =>
val result = f(x)
cache(arg) = result
result
}
def cachedF(arg: String): String = cache.get(arg) match
case Some(result) => result
case None =>
val result = f(x)
cache(arg) = result
result