Я хотел бы написать метод mergeKeys
, который группирует значения в Iterable[(K, V)]
по ключам. Например, я мог бы написать:
def mergeKeysList[K, V](iter: Iterable[(K, V)]) = {
iter.foldLeft(Map[K, List[V]]().withDefaultValue(List.empty[V])) {
case (map, (k, v)) =>
map + (k -> (v :: map(k)))
}
}
Однако я хотел бы иметь возможность использовать любой Monoid
вместо написания метода для List
. Например, значения могут быть целыми числами, и я хочу суммировать их, а не добавлять их в список. Или они могут быть кортежами (String, Int)
, где я хочу накапливать строки в наборе, но добавлять целые числа. Как я могу написать такой метод? Или есть что-то еще, что я могу использовать в scalaz, чтобы сделать это?
Обновление: я был не так далеко, как думал. Я стал немного ближе, но я все еще не знаю, как заставить это работать, если значения являются кортежами. Нужно ли мне писать еще одно неявное преобразование? Т.е. одно неявное преобразование для каждого числа параметров типа?
sealed trait SuperTraversable[T, U, F[_]]
extends scalaz.PimpedType[TraversableOnce[(T, F[U])]] {
def mergeKeys(implicit mon: Monoid[F[U]]): Map[T, F[U]] = {
value.foldLeft(Map[T, F[U]]().withDefaultValue(mon.zero)) {
case (map, (k, v)) =>
map + (k -> (map(k) |+| v))
}
}
}
implicit def superTraversable[T, U, F[_]](
as: TraversableOnce[(T, F[U])]
): SuperTraversable[T, U, F] =
new SuperTraversable[T, U, F] {
val value = as
}