Is there an elegant way in to update an already existing value in a Map?
This looks too scary:
val a = map.get ( something )
if ( a != null ) // case .. excuse my old language
a.apply( updateFunction )
else
map.put ( something, default )
Most of the time you can insert something that can be updated when it's created (e.g. if it's a count, you put 0 in it and then update to 1 instead of just putting 1 in to start). In that case,
map.getOrElseUpdate(something, default).apply(updateFunction)
In the rare cases where you can't organize things this way,
map(something) = map.get(something).map(updateFunction).getOrElse(default)
(but you have to refer to something
twice).
This is what I usually write... not sure if there are better solutions.
map.get(key) match {
case None => map.put(key, defaultValue)
case Some(v) => map(key) = updatedValue
}
In fact update
and put
are the same for mutable map, but I usually use update
on existing entries and put
for new ones, just for readability.
Another thing is that if you can figure out what the ultimate value is without checking the existence of the key, you can simply write map(key) = value
, at it automatically creates/replaces the entry.
Finally, statements like map(key) += 1
actually works in Map
(this is generally true for collections with update
function), and so do many simple numeric operations.\
To solve double put, use mutable object instead of immutable values:
class ValueStore(var value: ValueType)
val map = new Map[KeyType, ValueStore]
...
map.get(key) match {
case None => map.put(key, new ValueStore(defaultValue))
case Some(v) => v.value = updatedValue
}
As I mentioned in the comment, the underlying structure of HashMap
is HashTable
, which actually use this mutable wrapper class approach. HashMap
is a nicer wrap-up class but you sometimes just have to do duplicated computation.
me stupid, you are (quite) right:
map.get(key) match {
case None => map.put(key, defaultValue)
case Some(v) => v.apply(updateFunction) // changes state of value
}
tsts thanks