Scalaz имеет концепцию Полугруппа , которая фиксирует то, что вы хотите здесь сделать, и приводит, возможно, к кратчайшему / чистому решению:
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)
В частности, бинарный оператор для Map[K, V]
объединяет ключи карт, складывая оператор полугруппы V
по любым дублирующимся значениям. Стандартная полугруппа для Int
использует оператор сложения, поэтому вы получаете сумму значений для каждого дублирующего ключа.
Редактировать : немного больше деталей, согласно запросу пользователя 482745.
Математически полугруппа - это просто набор значений вместе с оператором, который принимает два значения из этого набора и создает другое значение из этого набора. Таким образом, при добавлении целые числа представляют собой полугруппу, например - оператор +
объединяет два целых числа для создания другого целого числа.
Вы также можете определить полугруппу по набору «всех карт с заданным типом ключа и типом значения», при условии, что вы можете придумать некоторую операцию, которая объединяет две карты, чтобы создать новую, которая каким-то образом является комбинацией из двух входов.
Если на обеих картах нет клавиш, это тривиально. Если один и тот же ключ существует на обеих картах, то нам нужно объединить два значения, на которые отображается ключ. Хм, разве мы не описали оператор, который объединяет два объекта одного типа? Вот почему в Scalaz полугруппа для Map[K, V]
существует тогда и только тогда, когда существует полугруппа для V
- полугруппа V
используется для объединения значений из двух карт, которые назначены одному и тому же ключу.
Так как Int
является здесь типом значения, «коллизия» на ключе 1
разрешается путем целочисленного сложения двух отображенных значений (как это делает оператор полугруппы Int), следовательно, 100 + 9
. Если бы значения были Strings, коллизия привела бы к объединению строк двух сопоставленных значений (опять же, потому что это то, что делает оператор полугруппы для String).
(И что интересно, поскольку конкатенация строк не является коммутативной, то есть "a" + "b" != "b" + "a"
, результирующая операция полугруппы также не является. Поэтому map1 |+| map2
отличается от map2 |+| map1
в случае String, но не в Int случай.)