I would like to write a method mergeKeys
that groups the values in an Iterable[(K, V)]
by the keys. For example, I could write:
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)))
}
}
However, I would like to be able to use any Monoid
instead of writing a method for List
. For example, the values may be integers and I want to sum them instead of appending them in a list. Or they may be tuples (String, Int)
where I want to accumulate the strings in a set but add the integers. How can I write such a method? Or is there something else I can use in scalaz to get this done?
Update: I wasn't as far away as I thought. I got a little bit closer, but I still don't know how to make it work if the values are tuples. Do I need to write yet another implicit conversion? I.e., one implicit conversion for each number of type parameters?
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
}