
{"id":438,"date":"2009-12-09T15:41:05","date_gmt":"2009-12-09T06:41:05","guid":{"rendered":"http:\/\/www.monomorphic.org\/wordpress\/?p=438"},"modified":"2009-12-09T17:45:23","modified_gmt":"2009-12-09T08:45:23","slug":"an-immutable-multimap-for-scala","status":"publish","type":"post","link":"https:\/\/www.monomorphic.org\/wordpress\/an-immutable-multimap-for-scala\/","title":{"rendered":"An immutable MultiMap for Scala"},"content":{"rendered":"<p>The Scala collections library (in version 2.7.7) has a MultiMap trait for mutable collections, but none for immutable ones. I hacked something up to use while waiting for an official version. I&#8217;m finding this to work well, but I don&#8217;t have much experience with collections design, so it&#8217;s likely to have some flaws. Also, this is a class and not a trait, so you can&#8217;t use it with any map you like. And from a concurrency perspective, maybe it&#8217;s sometimes better to use backing collections other than the HashSet and the HashMap.<\/p>\n<pre lang=\"scala\">\r\n\r\nimport scala.collection.immutable._\r\n\r\n\/**\r\nA multimap for immutable member sets (the Scala libraries \r\nonly have one for mutable sets). \r\n*\/\r\nclass MultiMap[A, B](val myMap: Map[A, Set[B]]) {\r\n\r\n\tdef this() = this(new HashMap[A, Set[B]])\r\n\r\n\tdef +(kv: Tuple2[A, B]): MultiMap[A, B] = {\r\n\t  val set = if (myMap.contains(kv._1)) {\r\n\t\t  myMap(kv._1) + kv._2\r\n\t  } else {\r\n\t\t  new HashSet() + kv._2\t     \t   \r\n\t  }\r\n\r\n\t  new MultiMap[A, B](myMap + ((kv._1, set)))\r\n\t}\r\n\t\r\n\tdef -(kv: Tuple2[A, B]): MultiMap[A, B] = {\r\n\t  if (!myMap.contains(kv._1)) {\r\n\t    throw new Exception(\"No such key\")\r\n\t  }\r\n\t  val set = myMap(kv._1) - kv._2\r\n\t  if (set.isEmpty) {\r\n\t    new MultiMap[A, B](myMap - kv._1)\r\n\t  } else {\r\n\t\t  new MultiMap[A, B](myMap + ((kv._1, set)))\r\n\t  }\r\n\t}\r\n \r\n\tdef entryExists(kv: Tuple2[A, B]): Boolean = {\r\n\t  if (!myMap.contains(kv._1)) {\r\n\t    false\r\n\t  } else {\r\n\t    myMap(kv._1).contains(kv._2)\r\n\t  }\r\n\t}\r\n \r\n    def keys = myMap.keys\r\n    \r\n     def values: Iterator[Set[B]] = myMap.values\r\n   \r\n    def getOrElse(key: A, elval: Collection[B]): Collection[B] = {      \r\n      myMap.getOrElse(key, elval)\r\n    }\r\n    \r\n    def apply(key: A) = myMap(key)\r\n \r\n    \r\n\t                                                        \r\n}\r\n\r\n<\/pre>\n<p>Usage:<\/p>\n<pre lang=\"scala\">\r\n\r\n   var theMultiMap = new MultiMap[String, Int]()\r\n\r\n   theMultiMap += ((\"george\", 1))\r\n   theMultiMap += ((\"george\", 3))\r\n   theMultiMap += ((\"bob\", 2))\r\n   theMultiMap -= ((\"george\", 1))\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The Scala collections library (in version 2.7.7) has a MultiMap trait for mutable collections, but none for immutable ones. I hacked something up to use while waiting for an official version. I&#8217;m finding this to work well, but I don&#8217;t have much experience with collections design, so it&#8217;s likely to have some flaws. Also, this [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[53],"tags":[43,9],"class_list":["post-438","post","type-post","status-publish","format-standard","hentry","category-dev","tag-code","tag-scala"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/py2qT-74","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/posts\/438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/comments?post=438"}],"version-history":[{"count":10,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/posts\/438\/revisions"}],"predecessor-version":[{"id":448,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/posts\/438\/revisions\/448"}],"wp:attachment":[{"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/media?parent=438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/categories?post=438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.monomorphic.org\/wordpress\/wp-json\/wp\/v2\/tags?post=438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}