集合

地图

语言

一个 Map 是一个 Iterable,它由键值对组成(也称为映射关联)。Scala 的 Predef 对象提供了一个隐式转换,允许您将 key -> value 作为 (key, value) 对的替代语法。例如 Map("x" -> 24, "y" -> 25, "z" -> 26)Map(("x", 24), ("y", 25), ("z", 26)) 的含义完全相同,但可读性更好。

地图上的基本操作类似于集合上的操作。它们在以下表格中总结,并分为以下类别

  • 查找 操作 applygetgetOrElsecontainsisDefinedAt。这些操作将映射转换为从键到值的偏函数。映射的基本查找方法是:def get(key): Option[Value]。操作 m.get(key) 测试映射是否包含给定 key 的关联。如果是,则返回 Some 中的关联值。如果映射中未定义任何键,则 get 返回 None。映射还定义了一个 apply 方法,该方法直接返回与给定键关联的值,而不会将其包装在 Option 中。如果映射中未定义键,则会引发异常。
  • 添加和更新 +++updated,这些操作允许您向映射添加新的绑定或更改现有的绑定。
  • 删除 ---,这些操作从映射中删除绑定。
  • 子集合生成器 keyskeySetkeysIteratorvaluesvaluesIterator,这些操作以各种形式分别返回映射的键和值。
  • 转换 filterKeysmapValues,这些操作通过过滤和转换现有映射的绑定来生成新的映射。

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) = valuem += (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

本页贡献者