Существует еще одна возможность использования Scalaz.
Ключевым моментом является то, что если M
является Monoid
, то Map[T, M]
также является Monoid
. Это означает, что если у меня есть 2 карты, m1
и m2
, я могу добавить их так, чтобы для каждого подобного ключа элементы были добавлены вместе.
Например, Map[String, List[String]]
- это моноид, потому что List[String]
- это Monoid
. Поэтому, учитывая соответствующий экземпляр Monoid
в области видимости, я должен быть в состоянии сделать:
val m1 = Map("a" -> List(1), "b" -> List(3))
val m2 = Map("a" -> List(2))
// |+| "adds" two elements of a Monoid together in Scalaz
m1 |+| m2 === Map("a" -> List(1, 2), "b" -> List(3))
По вашему вопросу мы можем видеть, что Map[String, Int]
- это Monoid
, потому что есть тип Monoid
для типа Int
. Давайте импортируем это:
implicit val mapMonoid = MapMonoid[String, Int]
Затем мне нужна функция reduceMonoid
, которая берет все, что является Traversable
и «добавляет» свои элементы с помощью Monoid
. Я просто пишу определение reduceMonoid
здесь, для полной реализации, пожалуйста, обратитесь к моему посту по Essence of the Iterator Pattern :
// T is a "Traversable"
def reduce[A, M : Monoid](reducer: A => M): T[A] => M
Эти 2 определения не существуют в текущей библиотеке Scalaz, но их нетрудно добавить (на основе существующих классов типов Monoid
и Traverse
). И как только мы их получим, решение вашего вопроса будет очень простым:
val s = Seq(("04-03-1985" -> 1.5),
("05-03-1985" -> 2.4),
("05-03-1985" -> 1.3))
// we just put each pair in its own map and we let the Monoid instance
// "add" the maps together
s.reduceMonoid(Map(_)) === Map("04-03-1985" -> 1.5,
"05-03-1985" -> 3.7)
Если вы чувствуете, что приведенный выше код немного неясен (но действительно лаконичен, верно?), Я рекомендую вам проверить проект github для поста EIP и поиграть с ним. Один пример показывает решение вашего вопроса:
"I can build a map String->Int" >> {
val map1 = List("a" -> 1, "a" -> 2, "b" -> 3, "c" -> 4, "b" -> 5)
implicit val mapMonoid = MapMonoid[String, Int]
map1.reduceMonoid(Map(_)) must_== Map("a" -> 3, "b" -> 8, "c" -> 4)
}