1

I'm trying to build a mutable map from integers to a mutable set of integers in Scala.

For example, I would like to have the mappings of the form 1 -> (2,3) and be able to update them later using the key value. The code that I use is as follows:

import scala.collection.mutable._

val map = Map[Int, Set[Int]]()
map: scala.collection.mutable.Map[Int,scala.collection.mutable.Set[Int]] = Map()

map += (1 -> Set(2,3))
res15: map.type = Map(1 -> Set(2, 3))

So far good, but when I try to do something like

map.get(1) += 4

I get an assignment to val error. What is confusing to me is that map.get() should return a Set of type scala.collection.mutable.Set which can be updated. Can someone please shed some light what's going on here?

Wickoo
  • 6,745
  • 5
  • 32
  • 45

2 Answers2

3

The issue in this case is that get() returns an option (Option[scala.collection.mutable.Set[Int]]), which you need to "unpack":

map.get(1).get += 4

The reason Map's get() function returns an option is that there might not be a value for any given key, and Scala does not like throwing exceptions like its Java API counterpart.

Alternatively you could use the apply() method, which directly returns the requested value and throws an exception in case of failure:

map(1) += 4

I haven't quite figured out why you'd get a "reassignment to val" error with the code you've tried, though. In my case (Scala 2.10), it says the following:

<console>:12: error: value += is not a member of Option[scala.collection.mutable.Set[Int]]
          map.get(1) += 1

Which version of Scala are you using?

fresskoma
  • 25,481
  • 10
  • 85
  • 128
  • Thanks! great answer. I'm on 2.9.2. Now I also have a good reason to upgrade. – Wickoo Jan 20 '13 at 21:59
  • Another question related to my previous one: if I define the collection as var map = Map[Int, Set[Int]](), this time with immutable collections but a var, again I get the error reassignment to val (I'm still on scala 2.9.2) when I try something like map(1) += 4. I think that's because Set[Int] is immutable. Do you know any workarounds for this case? – Wickoo Jan 21 '13 at 16:45
  • `Seq` doesn't even have a `+=` method. In any case, you won't be able to add anything to an immutable data structure, and if you'd find a way to do it, that would be a bug and should be fixed as soon as possible, given that in many cases, when using immutable data structures, you _rely_ on them being immutable. – fresskoma Jan 21 '13 at 17:44
  • Sorry, I think I explained in a misleading way. The better of asking is that how can I create a new Map[Int, Set[Int]] from an existing one, apply my changes and put the results back to the defined variable. If I don't have nested collections, it's OK, for example: `var map = Map((1->3),(2->3),(3->4))` and then `map += (2->4)` the result would be `scala.collection.immutable.Map[Int,Int] = Map(1 -> 3, 2 -> 4, 3 -> 4)` Here, Scala creates a new copy for me with changes applied. But when I have the nested Set inside it doesn't work. Is it more clear now? – Wickoo Jan 21 '13 at 18:59
  • 1
    If I understood your question correctly, you want to achieve what I explained in [this answer](http://stackoverflow.com/questions/14447242/how-to-modify-a-value-of-a-map-which-contains-sets-returning-a-new-map/14447243#14447243). – fresskoma Jan 21 '13 at 21:09
  • Yes, that works :) I however needed to add the default case to avoid Match exceptions. `x.map { case (1, v) => (1, v + 5) case x@_ => x }` – Wickoo Jan 21 '13 at 21:27
0

more elegant way is

map.get(1).map(_ += 4).getOrElse{map += 1 -> Seq(4)}
scaramush
  • 29
  • 2