Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access/initialize and update values in a mutable map?

Tags:

Consider the simple problem of using a mutable map to keep track of occurrences/counts, i.e. with:

val counts = collection.mutable.Map[SomeKeyType, Int]() 

My current approach to incrementing a count is:

counts(key) = counts.getOrElse(key, 0) + 1 // or equivalently counts.update(key, counts.getOrElse(key, 0) + 1) 

This somehow feels a bit clumsy, because I have to specify the key twice. In terms of performance, I would also expect that key has to be located twice in the map, which I would like to avoid. Interestingly, this access and update problem would not occur if Int would provide some mechanism to modify itself. Changing from Int to a Counter class that provides an increment function would for instance allow:

// not possible with Int counts.getOrElseUpdate(key, 0) += 1 // but with a modifiable counter counts.getOrElseUpdate(key, new Counter).increment 

Somehow I'm always expecting to have the following functionality with a mutable map (somewhat similar to transform but without returning a new collection and on a specific key with a default value):

// fictitious use counts.updateOrElse(key, 0, _ + 1) // or alternatively counts.getOrElseUpdate(key, 0).modify(_ + 1) 

However as far as I can see, such a functionality does not exist. Wouldn't it make sense in general (performance and syntax wise) to have such a f: A => A in-place modification possibility? Probably I'm just missing something here... I guess there must be some better solution to this problem making such a functionality unnecessary?

Update:

I should have clarified that I'm aware of withDefaultValue but the problem remains the same: performing two lookups is still twice as slow than one, no matter if it is a O(1) operation or not. Frankly, in many situations I would be more than happy to achieve a speed-up of factor 2. And obviously the construction of the modification closure can often be moved outside of the loop, so imho this is not a big issue compared to running an operation unnecessarily twice.

like image 321
bluenote10 Avatar asked Mar 19 '13 16:03

bluenote10


People also ask

How do you access map elements in Scala?

Scala Map get() method with exampleThe get() method is utilized to give the value associated with the keys of the map. The values are returned here as an Option i.e, either in form of Some or None. Return Type: It returns the keys corresponding to the values given in the method as argument.

How do I add values to a map in Scala?

Adding new key-value pair We can insert new key-value pairs in a mutable map using += operator followed by new pairs to be added or updated.

How do you add a mutable map?

Add elements to a mutable map by simply assigning them, or with the += method. Remove elements with -= or --= . Update elements by reassigning them.

How can we convert mutable map to immutable Scala?

If you just want a mutable HashMap , you can just use x. toMap in 2.8 or collection. immutable. Map(x.


1 Answers

You could create the map with a default value, which would allow you to do the following:

scala> val m = collection.mutable.Map[String, Int]().withDefaultValue(0) m: scala.collection.mutable.Map[String,Int] = Map()  scala> m.update("a", m("a") + 1)  scala> m res6: scala.collection.mutable.Map[String,Int] = Map(a -> 1) 

As Impredicative mentioned, map lookups are fast so I wouldn't worry about 2 lookups.

Update:

As Debilski pointed out you can do this even more simply by doing the following:

scala> val m = collection.mutable.Map[String, Int]().withDefaultValue(0) scala> m("a") += 1 scala> m  res6: scala.collection.mutable.Map[String,Int] = Map(a -> 1) 
like image 155
coltfred Avatar answered Sep 25 '22 10:09

coltfred