一个 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