Nice way to add number to element in Scala map if key exists or insert new element it not

The shortest way to do that:

a += a.get(key).map(x => key -> (x + 5)).getOrElse("k5" -> 200)

In general:

a += a.get(k).map(f).map(k -> _).getOrElse(kv)

Same if your dictionary is immutable:

m + m.get(k).map(f).map(k -> _).getOrElse(kv)

so I don't see any reason to use mutable collection here.

If you don't like all these Option.map things:

m + (if (m.contains(k)) k -> f(m(k)) else kv)

Note, that there is a whole class of possible variations:

k1 -> f(m(k1)) else k2 -> v2 //original
k1 -> f(m(k1)) else k1 -> v2
k1 -> f(m(k2)) else k2 -> v2
k1 -> f(m(k2)) else k1 -> v2
k2 -> v2 else k1 -> f(m(k1)) 
k1 -> v2 else k1 -> f(m(k1))
k2 -> v2 else k1 -> f(m(k2))
k1 -> v2 else k1 -> f(m(k2))
... //v2 may also be a function from some key's value

So, Why it's not a standard function? IMO, because all variations still can be implemented as one-liners. If you want library with all functions, that can be implemented as one-liners, you know, it's Scalaz :).

P.S. If yu also wonder why there is no "update(d) if persist" function - see @Rex Kerr 's answer here


You can create you own function for that purpose:

def addOrUpdate[K, V](m: collection.mutable.Map[K, V], k: K, kv: (K, V), 
                      f: V => V) {
  m.get(k) match {
    case Some(e) => m.update(k, f(e))
    case None    => m += kv
  }
}

addOrUpdate(a, "k1", "k5" -> 200, (v: Int) => v + 5)

Scala 2.13 introduced updatedWith method which seems to be the most idiomatic way to update a map conditionally on the existence of the key.

val a = Map(("k1" -> 1), ("k2" -> 5))

val a1 = a.updatedWith("k1") { 
  case Some(v) => Some(v + 5)
  case None => Some(200) 
}
println(a1) // Map(k1 -> 6, k2 -> 5)

One may also remove values using it:

val a2 = a.updatedWith("k2") { 
  case Some(5) => None
  case v => v 
}
println(a2) // Map(k1 -> 1)

An excerpt from the Scala Standard Library reference:

def updatedWith[V1 >: V](key: K)(remappingFunction: (Option[V]) => Option[V1]): Map[K, V1]

Update a mapping for the specified key and its current optionally-mapped value (Some if there is current mapping, None if not).

If the remapping function returns Some(v), the mapping is updated with the new value v. If the remapping function returns None, the mapping is removed (or remains absent if initially absent). If the function itself throws an exception, the exception is rethrown, and the current mapping is left unchanged.