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’m finding this to work well, but I don’t have much experience with collections design, so it’s likely to have some flaws. Also, this is a class and not a trait, so you can’t use it with any map you like. And from a concurrency perspective, maybe it’s sometimes better to use backing collections other than the HashSet and the HashMap.
import scala.collection.immutable._ /** A multimap for immutable member sets (the Scala libraries only have one for mutable sets). */ class MultiMap[A, B](val myMap: Map[A, Set[B]]) { def this() = this(new HashMap[A, Set[B]]) def +(kv: Tuple2[A, B]): MultiMap[A, B] = { val set = if (myMap.contains(kv._1)) { myMap(kv._1) + kv._2 } else { new HashSet() + kv._2 } new MultiMap[A, B](myMap + ((kv._1, set))) } def -(kv: Tuple2[A, B]): MultiMap[A, B] = { if (!myMap.contains(kv._1)) { throw new Exception("No such key") } val set = myMap(kv._1) - kv._2 if (set.isEmpty) { new MultiMap[A, B](myMap - kv._1) } else { new MultiMap[A, B](myMap + ((kv._1, set))) } } def entryExists(kv: Tuple2[A, B]): Boolean = { if (!myMap.contains(kv._1)) { false } else { myMap(kv._1).contains(kv._2) } } def keys = myMap.keys def values: Iterator[Set[B]] = myMap.values def getOrElse(key: A, elval: Collection[B]): Collection[B] = { myMap.getOrElse(key, elval) } def apply(key: A) = myMap(key) } |
Usage:
var theMultiMap = new MultiMap[String, Int]() theMultiMap += (("george", 1)) theMultiMap += (("george", 3)) theMultiMap += (("bob", 2)) theMultiMap -= (("george", 1)) |
Post a Comment