O Scalaz tem o conceito de um semigrupo que captura o que você quer fazer aqui e leva à possível solução mais curta / limpa:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val map1 = Map(1 -> 9 , 2 -> 20)
map1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 9, 2 -> 20)
scala> val map2 = Map(1 -> 100, 3 -> 300)
map2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 100, 3 -> 300)
scala> map1 |+| map2
res2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 109, 3 -> 300, 2 -> 20)
Especificamente, o operador binário para Map[K, V]
combina as chaves dos mapas, dobrando V
o operador do semigrupo sobre quaisquer valores duplicados. O semigrupo padrão para Int
usa o operador de adição, para que você obtenha a soma dos valores para cada chave duplicada.
Editar : um pouco mais detalhadamente, conforme a solicitação do usuário482745.
Matematicamente, um semigrupo é apenas um conjunto de valores, junto com um operador que pega dois valores desse conjunto e produz outro valor a partir desse conjunto. Portanto, números inteiros em adição são um semigrupo, por exemplo - o +
operador combina duas entradas para criar outra int.
Você também pode definir um semigrupo sobre o conjunto de "todos os mapas com um determinado tipo de chave e tipo de valor", desde que seja possível criar alguma operação que combine dois mapas para produzir um novo, que seja de alguma forma a combinação dos dois entradas.
Se não houver teclas que apareçam nos dois mapas, isso é trivial. Se a mesma chave existir nos dois mapas, precisamos combinar os dois valores para os quais a chave é mapeada. Hmm, não acabamos de descrever um operador que combina duas entidades do mesmo tipo? É por isso que no Scalaz Map[K, V]
existe um semigrupo para se, e somente se, um semigrupo para V
existir - V
é usado para combinar os valores de dois mapas atribuídos à mesma chave.
Portanto, como Int
é o tipo de valor aqui, a "colisão" na 1
chave é resolvida pela adição inteira dos dois valores mapeados (como é o que o operador de semigrupo do Int faz), portanto 100 + 9
. Se os valores tivessem sido Strings, uma colisão resultaria na concatenação de string dos dois valores mapeados (novamente, porque é isso que o operador de semigrupo para String faz).
(E, curiosamente, porque a concatenação de strings não é comutativa - ou seja, "a" + "b" != "b" + "a"
- a operação de semigrupo resultante também não é. Portanto, map1 |+| map2
é diferente do map2 |+| map1
caso String, mas não no caso Int).
map1 ++ map2