4

if I'm using the Scala Multimap, and I want to get the values associated with a key or else the empty set, do I have to write the following?

multimap.getOrElse("key", new collection.mutable.HashSet())

It would seem that the following should just work. An empty set seems like a good default value.

multimap.getOrElse("key")
schmmd
  • 18,650
  • 16
  • 58
  • 102

4 Answers4

4

Normally you would use Map.withDefaultValue for this. However, it looks as if you can't really get this behavior and still have a collection typed as a MultiMap[A, B]. The return type of MultiMap.withDefaultValue is Map[A, Set[B]]. So unfortunately you'll have to abandon the use of the MultiMap mixin to get the behavior you desire.

Garrett Rowe
  • 1,205
  • 9
  • 13
3

As you observed, the MultiMap trait doesn't do what you want. However, you can add a default value yourself if the Map is specifically mutable or immutable. Here's an example,

scala> val m = collection.mutable.Map(1 -> 2)
m: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala> val m2 = m.withDefaultValue(42)
m2: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)

scala> m2(1)
res0: Int = 2

scala> m2(2)
res1: Int = 42

Strangely, the above won't work if the type of m is an abstract collection.Map. The comment in the source code says this is due to variance issues.

Kipton Barros
  • 21,002
  • 4
  • 67
  • 80
0

Since, as Garrett Rowe noted, withDefaultValue doesn't preserve the proper MultiMap type when using the mixin, you can instead override the default method in an anonymous class and preserve the behavior of MultiMap:

scala> import collection.mutable.{ HashMap, MultiMap, Set }
import collection.mutable.{HashMap, MultiMap, Set}

scala> val map: MultiMap[String, Int] = new HashMap[String, Set[Int]] with MultiMap[String, Int] {
     |   override def default(key: String): Set[Int] = Set.empty[Int]
     | }
map: scala.collection.mutable.MultiMap[String,Int] = Map()

scala> map("foo")
res0: scala.collection.mutable.Set[Int] = Set()

scala> map.addBinding("foo", 1)
res1: map.type = Map(foo -> Set(1))

scala> map("foo")
res2: scala.collection.mutable.Set[Int] = Set(1)
Community
  • 1
  • 1
ches
  • 6,382
  • 2
  • 35
  • 32
0

The withDefaultValue can be use for this use case. For instance:

import collection.mutable._
val multimap = Map[String, HashSet[String]]() withDefaultValue(new HashSet())
scala> multimap("key")
// res1: scala.collection.mutable.HashSet[String] = Set()
huynhjl
  • 41,520
  • 14
  • 105
  • 158
  • This doesn't seem to work as expected. `multimap("key") += "value"` doesn't modify the map. I'm guessing default values aren't cached. – Brian McCutchon May 02 '17 at 18:29