一個 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 |
移除 ks 中所有鍵於 ms 中,並回傳 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
相關聯的值,或 None
(如果 key
之前不存在於映射中)。
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
的第二個參數是依名稱傳遞的,因此只有在 getOrElseUpdate
需要其第二個參數的值時,才會執行 f("abc")
的運算,也就是當其第一個參數未在 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