マップ | 目次 |
最新版は Scala Documentation に移行しました。
マップ (Map) はキーと値により構成されるペアの Iterable の一種で、写像 (mapping) や関連 (association) とも呼ばれる。Scala の Predef クラスは、ペアの (key, value) を key -> value と書けるような暗黙の変換を提供する。例えば、Map("x" -> 24, "y" -> 25, "z" -> 26) は Map(("x", 24), ("y", 25), ("z", 26)) と全く同じことを意味するがより可読性がある。
マップの基本的な演算は集合のものと似ている。それらは、以下の表 にまとめられており、以下のカテゴリーに分類できる:
def get(key): Option[Value] |
"m get key" という演算はマップが key に関連する値があるかを調べる。もしあれば、マップはその関連する値を Some に包んで返す。key がマップ中に定義されていなければ get は None を返す。マップはまた、任意のキーに関連する値を Option に包まずに直接返す apply メソッドも定義する。マップにキーが定義されていない場合は、例外が発生する。
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 + (k -> v) | ms 内の全ての写像と、キー k から値 v への写像 k -> v を含むマップ。 |
ms + (k -> v, l -> w) | ms 内の全ての写像と、渡されたキーと値のペアを含むマップ。 |
ms ++ kvs | ms 内の全ての写像と、kvs内の全てのキーと値のペアを含むマップ。 |
ms updated (k, v) | ms + (k -> v) に同じ。 |
減算: | |
ms - k | キー k からの写像を除く、ms 内の全ての写像。 |
ms - (k, l, m) | 渡されたキーからの写像を除く、ms 内の全ての写像。 |
ms -- ks | ks内のキーからの写像を除く、ms 内の全ての写像。 |
サブコレクション取得演算: | |
ms.keys | ms内の全てのキーを含む iterable。 |
ms.keySet | ms内の全てのキーを含む集合。 |
ms.keysIterator | ms内の全てのキーを返すイテレータ。 |
ms.values | ms内のキーに関連付けられた全ての値を含む iterable。 |
ms.valuesIterator | ms内のキーに関連付けられた全ての値を返すイテレータ。 |
変換演算: | |
ms filterKeys p | キーが条件関数 p を満たす ms内の写像のみを含むマップのビュー。 |
ms mapValues f | ms内のキーに関連付けられた全ての値に関数 f を適用して得られるマップのビュー。 |
可変マップ (mutable.Map) は他にも以下の表にまとめた演算をサポートする。
mutable.Map トレイトの演算 | |
---|---|
使用例 | 振る舞い |
加算と更新演算: | |
ms(k) = v | (展開した場合、ms.update(x, v))。マップ ms に副作用としてキー k から値 v への写像を加え、既に k からの写像がある場合は上書きする。 |
ms += (k -> v) | マップ ms に副作用としてキー k から値 v への写像を加え、ms自身を返す。 |
ms += (k -> v, l -> w) | マップ ms に副作用として渡された写像を加え、ms自身を返す 。 |
ms ++= kvs | マップ ms に副作用として kvs内の全ての写像を加え、ms自身を返す。 |
ms put (k, v) | マップ ms にキー k から値 v への写像を加え、以前の k からの写像のオプション値を返す。 |
ms getOrElseUpdate (k, d) | マップ ms内にキー k が定義されている場合は、関連付けられた値を返す。定義されていない場合は、ms に写像 k -> d を加え、d を返す。 |
減算: | |
ms -= k | マップ ms から副作用としてキー k からの写像を削除して、ms自身を返す。 |
ms -= (k, l, m) | マップ ms から副作用として渡されたキーからの写像を削除して、ms自身を返す。 |
ms --= ks | マップ ms から副作用として ks内の全てのキーからの写像を削除して、ms自身を返す。 |
ms remove k | マップ ms からキー k からの写像を削除して、以前の k からの写像のオプション値を返す。 |
ms retain p | ms内の写像でキーが条件関数 p を満たすものだけを残す。 |
ms.clear() | ms から全ての写像を削除する。 |
変換演算: | |
ms transform f | マップ ms内の全ての関連付けされた値を関数 f を使って変換する。 |
クローン演算: | |
ms.clone | ms と同じ写像を持つ新しい可変マップを返す。 |
マップの加算と減算は、集合のそれにならう。集合と同様、非破壊的な演算である +, -, と updated を提供するが、加算マップをコピーする必要があるため、これらはあまり使われることがない。そのかわり、可変マップは通常 m(key) = value か m += (key -> value) という二種類の更新演算を使って上書き更新される。さらに前に key から関連付けされていた値を Option値で返すか、マップに key が無ければ None を返すというバリアントである m put (key, value) もある。
getOrElseUpdate はキャッシュとして振る舞うマップにアクセスするのに役立つ。例えば、関数 f により呼び出される時間のかかる計算があるとする:
scala> def f(x: String) = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
println("taking my time."); sleep(100) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
x.reverse } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
f: (x: String)String |
さらに、f には副作用を伴わず、同じ引数で何回呼び出しても同じ戻り値が返ってくると仮定する。この場合、引数と以前の f 計算結果の対応関係をマップに格納して、引数がマップに無いときだけ f の結果を計算すれば時間を節約できる。この時、マップは関数 f の計算のキャッシュであると言える。
val cache = collection.mutable.Map[String, String]() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cache: scala.collection.mutable.Map[String,String] = Map() |
これにより、より効率的な、キャッシュするバージョンの関数 f を作成することができる。
scala> def cachedF(s: 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 の第二引数は「名前渡し」(by-name) であるため、上の f("abc") は getOrElseUpdate が必要とする場合、つまり第一引数が cache に無い場合においてのみ計算されることに注意してほしい。 cachedF をより率直に、普通の map 演算を用いて実装することもできるが、コードは少し長くなる:
def cachedF(arg: String) = cache get arg match { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
case Some(result) => result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
case None => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
val result = f(x) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cache(arg) = result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
result | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
続いては、
マップ | 目次 |