S-JIS[2011-04-02/2013-06-08] 変更履歴

Scala Map

ScalaコレクションのMapについてのメモ。


概要

マップは、キーとなるオブジェクト(文字列やSymbol等)に対し、それに該当する値を保持するコレクション
他言語のマップ(ディクショナリー・連想配列)


ScalaのMap[K,V]はIterable[(K,V)]を継承している。
つまり標準的な追加・繰り返し処理はキーと値のペアタプル)で行う。

JavaのMapで繰り返し処理を行う場合、map.keySet().iterator()でキー、map.values().iterator()で値、map.entrySet().iterator()でキーと値(Entry)を対象とするので、
ScalaのMapのiteratorはentrySet().iterator()に相当する。


Mapのクラス

Map関連のクラス。

  パッケージ名 クラス名
(オブジェクト名)
備考 参考
共通 scala.collection Map[K,V] 不変・可変共通のMapトレイト。 マップ
不変 scala.collection.immutable Map[K,V] 不変マップ。  
scala.collection.immutable HashMap[K,V] ハッシュコードを使用しているMap。 ハッシュトライ
scala.collection.immutable TreeMap[K,V] キーが自然な順序で並ぶMap。 赤黒木
scala.collection.immutable IntMap[V]
LongMap[V]
キーがInt・LongであるMap。  
scala.collection.immutable ListMap[K,V] 内部がリスト構造をしているMap。 リストマップ
可変 scala.collection.mutable Map[K,V] 可変マップ。  
scala.collection.mutable HashMap[K,V] ハッシュコードを使用しているMap。 ハッシュテーブル
scala.collection.mutable LinkedHashMap[K,V] キーが追加した順番であるMap。  
scala.collection.mutable MultiMap[K,V] 値が複数持てる(Set[V]である)Map。  
scala.collection.mutable WeakHashMap[K,V] Javaの弱参照マップのラッパー。 弱ハッシュテーブル
scala.collection.mutable ListMap[K,V] 内部構造にListを使用しているMap。  
scala.collection.mutable SynchronizedMap[K,V] 同期化する為のトレイト  
scala.collection.mutable ConcurrentMap[K,V] JavaのConcurrentMapトレイト 並行マップ
scala.collection.concurrent TrieMap[K,V] [2013-06-08]  

インスタンス生成

Mapのインスタンスを作る(初期化する)方法。

クラス
オブジェクト
メソッド 備考
コーディング 結果
Map empty 空のMapを返す。 Map.empty[String, Int] Map[String,Int]()
Map("A"->123).empty Map[String,Int]()
Map apply 初期値(キーと値)を指定する。 Map("A"->123, "B"->456) Map((A,123), (B,456))
Traversable
(Seq・List)
toMap タプル2SeqからMapに変換する。 List("A"->123, "B"->456).toMap Map((A,123), (B,456))
不変Map withDefault
withDefaultValue
“キーが存在しない場合にデフォルト値を返すMap”を生成する。    
可変Map clone 複製を作成する。 Map("A"->123).clone Map((A,123))

不変Mapでは、要素数が1〜4個の場合は直接フィールドにキー・値を保持する特別なクラスが用意されており、内部で使用されている。
これは、要素数が少ないなら変に構造を用意するよりも速いからだろう。
要素数が5個を超えるとHashMapが使われる。


Mapのメソッド

Map関連のメソッド。
(→Iterable・Traversableのメソッド

 

クラス メソッド 備考
名称 引数 戻り型 演算 結果
要素の取得
Map[K,V] apply   key: K V キーに該当する値を返す。
無い場合は例外発生。
val m = Map('a->11, 'b->22, 'c->33)
m('b)
22
Map[K,V] get   key: K Option[V] キーに該当する値をOptionに入れて返す。
無い場合はNone。
val m = Map('a->11, 'b->22, 'c->33)
m.get('b)
Some(22)
Map[K,V] getOrElse V1 key: K
default: =>V1
V1 キーに該当する値を返す。
無い場合はdefaultを返す。
引数defaultは関数であり、要素が無いときしか呼ばれない。
val m = Map('a->11, 'b->22, 'c->33)
m.getOrElse('b, 99)
m.getOrElse('z, 99)
22
99
可変Map[K,V] getOrElseUpdate   key: K
op: =>V
V キーに該当する値がある場合、その値を返す。
無い場合はopで更新し、その値を返す。
引数opは関数であり、要素が無いときしか呼ばれない。
val m = Map('a->11, 'c->33)
m.getOrElseUpdate('b, 9)
m.getOrElseUpdate('b, 789)
9
9
Map[K,V] default   key: K V withDefaultwithDefaultValueによって作られたMapの場合、
そのデフォルト値を返す。
それ以外のMapでは例外が発生する。
val m = Map(1->"abc").withDefault(_.toString)
m.default(1)
1
TreeMap[K,V] firstKey     K 先頭(最小)のキーを返す。 val tm = TreeMap(1->"abc", 2->"def", 3->"ghi")
tm.firstKey
tm.lastKey
1
TreeMap[K,V] lastKey     K 末尾(最大)のキーを返す。 3
TreeMap[K,V] compare   k0: K
k1: K
Int TreeMapの比較順序で比較する。 val tm = TreeMap(1->"abc")
tm.compare(10, 99)
tm.compare(10, 10)
tm.compare(99, 10)
-1
0
1
TreeMap[K,V] isSmaller   x: K
y: K
Boolean TreeMapの比較順序で比較する。
x<yのときtrue。
val tm = TreeMap(1->"abc")
tm.isSmaller(10, 99)
tm.isSmaller(10, 10)
tm.isSmaller(99, 10)
true
false
false
Map[K,V] contains   key: K Boolean キーが存在したらtrue。 Map('a->11).contains('a) true
Map[K,V] isDefinedAt   key: K Boolean containsと同じ。 Map('a->11).isDefinedAt('a) true
MultiMap[K,V] entryExists   key: K
p: (V)=>Boolean
Boolean      
要素の追加・更新
Map[K,V] updated V1 key: K
value: V1
Map[K,V1] キーと値が追加(更新)された新しいMapを返す。 val m = Map(1->"abc")
m.updated(2, "def")
Map((1,abc), (2,def))
Map[K,V] + V1 kv: (K,V1)
kvs: (K,V1)*
Map[K,V1] キーと値が追加(更新)された新しいMapを返す。 Map(1->"abc") + (2->"def")
Map(1->"abc") + (2->"def", 3->"ghi")
Map((1,abc), (2,def))
Map((1,abc), (2,def), (3,ghi))
Map[K,V] ++ V1 xs: TraversableOnce[(K,V1)] Map[K,V1] 要素がタプル2である他コレクションを追加したMapを返す。 Map(1->"abc") ++ Map(2->"def") ++ List(3->"ghi") Map((1,abc), (2,def), (3,ghi))
TreeMap[K,V] insert V1 key: K
value: V1
Map[K,V1] キーと値が追加された新しいTreeMapを返す。
キーが既に存在している場合はAssertionErrorが発生する。
val tm = TreeMap(1->"abc")
tm.insert(2, "def")
Map((1,abc), (2,def))
Map[K,V] -   key: K
ks: K*
Map[K,V] キーが削除された新しいMapを返す。 val m = Map("abc"->1, "def"->2, "ghi"->3)
m - "def"
m - ("def", "ghi")
Map((abc,1), (ghi,3))
Map((abc,1))
要素の追加・更新・削除(可変コレクションのみ)
可変Map[K,V] put   key: K
value: V
Option[V] 値を更新(追加)し、元の値をOptionに入れて返す。 val m = Map("abc"->1)
m.put("def", 2)
m
m.put("def", 3)
m
None
Map((def,2), (abc,1))
Some(2)
Map((def,3), (abc,1))
可変Map[K,V] update   key: K
value: V
Unit 値を更新(追加)する。
updateの省略形
val m = Map("abc"->1)
m("def") = 2
m
m("def") = 3
m
Map((def,2), (abc,1))
Map((def,3), (abc,1))
可変Map[K,V] +=   kv: (K,V) 自分 値を更新(追加)する。 val m = Map("abc"->1)
m += "def"->2
m += "def"->3
Map((def,2), (abc,1))
Map((def,3), (abc,1))
可変Map[K,V] remove   key: K Option[V] キーを削除し、元の値をOptionに入れて返す。 val m = Map("abc"->1)
m.remove("abc")
m.remove("abc")
Some(1)
None
可変Map[K,V] -=   key: K 自分 キーを削除する。 val m = Map("abc"->1, "def"->2)
m -= "abc"
m -= "abc"
Map((def,2))
Map((def,2))
可変Map[K,V] clear     Unit 全要素を削除する。
emptyを使って新しいMapを作る方が速いかも?)
val m = Map("abc"->1)
m.clear()
m
Map()
MultiMap[K,V] addBinding   key: K
value: V
自分      
MultiMap[K,V] removeBinding   key: K
value: V
自分      
条件判定による要素・サブコレクションの取得
Map[K,V] filterKeys   p: (K)=>Boolean Map[K,V] 条件を満たす要素だけのMapを返す。 Map(1->"a",2->"b",3->"c").filterKeys(k => k%2==1) Map((1,a), (3,c))
可変Map[K, V] retain   p: (K,V)=>Boolean 自分 条件を満たす要素だけ残す。
(その他を削除する)
val m = Map("abc"->1, "d"->2, "ghi"->3)
m.retain((k,v)=> k.length==3)
Map((ghi,3), (abc,1))
全要素の順次処理
Map[K,V] mapValues V2 f: (V)=>V2 Map[K,V2] 値を変更した新しいMapを返す。 Map("a"->1, "b"->2, "c"->3).mapValues("v" + _) Map((a,v1), (b,v2), (c,v3))
Map[K,V] transform   f: (K,V)=>V Map[K, V] 可変Mapの場合は自分の値を変換する。
不変Mapの場合は新しいMapを返す。
val m = Map(1->2,3->4,5->6)
m.transform((k,v) => k+v)
Map((1,3), (3,7), (5,11))
Map[K,V] iterator     Iterator[(K,V)] キーと値のペアのIteratorを返す。
JavaのentrySet().iterator()に相当。
   
Map[K,V] keysIterator     Iterator[K] キーのIteratorを返す。
JavaのkeySet().iterator()に相当。
   
Map[K,V] valuesIterator     Iterator[V] 値のIteratorを返す。
Javaのvalues().iterator()に相当。
   
別のコレクションへの変換
不変Map[K,V] withDefault V1 d: (K)=>V1 Map[K,V1] applygetでキーが存在しない場合に
関数dを呼び出した結果(d(キー))を返す
というMapを返す。
val dm = Map(1->"abc").withDefault(_.toString)
dm(1)
dm(9)
abc
9
不変Map[K,V] withDefaultValue V1 d: V1 Map[K,V1] applygetでキーが存在しない場合にdを返す
というMapを返す。
val dm = Map(1->"abc").withDefaultValue("zzz")
dm(1)
dm(9)
abc
zzz
Map[K,V] keySet     Set[K] キーのSetを返す。
JavaのkeySet()に相当。
Map("abc"->1, "def"->2).keySet Set(abc, def)
Map[K,V] keys     Iterable[K] キーのIterableを返す。
(中身はkeySetと同じ)
Map("abc"->1, "def"->2).keys Set(abc, def)
Map[K,V] values     Iterable[V] 値のIterableを返す。
Javaのvalues()に相当。
Map("abc"->1, "def"->2).values MapLike(1, 2)

Mapの定石

Mapを使う際のセオリー(だと思うもの)。[2011-04-10]
JavaのMapの定石

パターン コーディング例 備考
値の取得
val v = map(key)
val v = map.apply(key)
値が存在しないときはNoSuchElementExceptionが発生する。
(→applyメソッドは「apply」を省略できる
val v = try {
  map.apply(key)
} catch {
  case _:NoSuchElementException => デフォルト値
}
val v = map.get(key) match {
  case Some(v) => v
  case _ => デフォルト値
}
val v = map.getOrElse(key, デフォルト値)
val m = map.withDefaultValue(デフォルト値)
val v = m.apply(key)
値が存在しないときにデフォルト値を使用する方法。
getOrElseの第2引数(デフォルト値)の型は実は関数なので、newによるインスタンス生成とかを書いても、
実際にデフォルト値が必要になったときしか呼ばれない(余計なインスタンス生成は行われない)。
if (map.contains(key)) {
  val v = map.apply(key)
  println(v)
}
map.get(key) match {
  case Some(v) => println(v)
  case _       =>
}
map.get(key).foreach { v =>
  println(v)
}
値があるときだけ何らかの処理をする方法。
val v = map.get(key) match {
  case Some(v) => v
  case _ =>
    val value = 初期値
    map += key -> value
    value
}
val v = map.getOrElseUpdate(key, 初期値)
要素が存在しなかったときに初期値をセットして使用する方法。
getOrElseUpdateは可変Mapでしか使えないが。
(getOrElseUpdateの第2引数の型も(getOrElseと同じく)関数なので、要素が存在しないときしか呼ばれない)
値の設定
(登録・更新)
map += key -> value
map(key) = value
map.update(key, value)
map.put(key, value)
val newMap = map.updated(key, value)
不変Map(通常のMap)の場合、更新は出来ないので、変数自身がvalでなくvarで束縛されている必要がある。
updateメソッドは可変Mapでしか使えない。
(→updateメソッドは代入文のような書き方が出来る
map ++= otherMap
val newMap = map ++ otherMap
他のMap(キーと値のペア(タプル)であるSeqでも可)を追加する方法。
キーと値一覧の取得
val i = map.iterator
while(i.hasNext) {
  val (k,v) = i.next
  println(k + "=" + v)
}
for (kv <- map) {
  val (k,v) = kv
  println(k + "=" + v)
}

for ((k,v) <- map) {
  println(k + "=" + v)
}
map.foreach { kv =>
  val (k,v) = kv
  println(k + "=" + v)
}

map.foreach { case (k,v) =>
  println(k + "=" + v)
}
Javaの様にIteratorも使えるし、JDK1.5以降のforeach構文のようなものも使えるが、
Scalaではコレクションに対するメソッドが豊富に用意されているので、そちらを使うのが腕の見せ所。
キー一覧の取得
val iterable = map.keys
val set = map.keySet
val i = map.keysIterator
 
値一覧の取得
val iterable = map.values
val i = map.valuesIterator
 

コレクションへ戻る / Scala目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま