LoginSignup
5
5

More than 5 years have passed since last update.

JavaでもScalaでも便利で重宝するMultiMap

Last updated at Posted at 2014-04-21

はじめに

Mapの値型にSeq、Set、Listあたりを取るときにありがちなコード。
キーが無かったらコレクションをnewして・・・という部分を書くのがかったるい。
※scala.mutable.Seqなどは値の追加をすると新しいコレクションが返ってきてしまうのでここではListBufferを使った。

val m = mutable.Map.empty[Int, ListBuffer[String]]

def addKeyValue(k: Int, v: String) = {
  if (!m.contains(k)) {
    m += (k -> new ListBuffer[String])
  }

  m(k) += v
}

MultiMapでリファクタリング

こんな時は、scala.collection.mutable.MultiMapを使うとスッキリ書ける。
MultiMapはtraitであり、具象クラスが用意されていないので以下のようにmix-inして使うのが基本となる。

val m = new mutable.HashMap[Int, mutable.Set[String]] with mutable.MultiMap[Int, String]

def addKeyValue(k: Int, v: String) = m.addBinding(k, v)

但し、MultiMapの値はSet型になるので注意が必要だ。以下のように宣言されている。
TreeSetのような順序を保持できるSetを使うことも出来ない。

trait MultiMap[A, B] extends Map[A, Set[B]] {

自作するにしても、MultiMapのソースコードはたかだかこの程度でありそんなに難しいものでもないだろう。

おまけ

なお、最初のコードは以下のようにMap#getOrElseUpdateメソッドを使うことでもう少し簡潔に書くことも出来る。

val m = mutable.Map.empty[String, ListBuffer[String]]

def addKeyValue(k: String, v: String) = {
  val l = m.getOrElseUpdate(k, new mutable.ListBuffer[String])
  l += v
}

Java編

あと、Javaでは標準ライブラリには存在しないものの、Google製guavaライブラリには同名のMultiMapが存在する。
同様にif文が不要になり重宝する。

Multimap<Int, String> m = ArrayListMultimap.create();
m.put(1, "one");
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5