Grupo de valores de uma chave com qualquer mesmo instalar os binários gerados
Pergunta
Eu gostaria de escrever um método mergeKeys
que grupos de valores em uma Iterable[(K, V)]
por chaves.Por exemplo, eu poderia escrever:
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)))
}
}
No entanto, eu gostaria de ser capaz de usar qualquer Monoid
em vez de escrever um método para List
.Por exemplo, os valores podem ser números inteiros e quero soma-las, em vez de acrescentá-los em uma lista.Ou eles podem ser tuplas (String, Int)
onde eu quero acumular-se as seqüências de caracteres em um conjunto, mas adicionar os números inteiros.Como posso escrever um método?Ou há algo mais que eu possa usar em scalaz para conseguir este feito?
Atualização:Eu não estava tão longe quanto eu pensei.Eu tenho um pouco mais de perto, mas eu ainda não sei como fazê-lo funcionar, se os valores são de tuplas.Eu preciso escrever ainda outro conversão implícita?I. e., uma conversão implícita para cada número de parâmetros do tipo?
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
}
Solução
Primeiro, embora não seja relevante para a sua pergunta, você está limitando o seu código
a generalidade por mencionar explicitamente o tipo de construtor F[_]
.Ele funciona muito bem
sem fazê-lo:
sealed trait SuperTraversable[K, V]
extends scalaz.PimpedType[TraversableOnce[(K, V)]] {
def mergeKeys(implicit mon: Monoid[V]): Map[K, V] = {
value.foldLeft(Map[K, V]().withDefaultValue(mon.zero)) {
case (map, (k, v)) =>
map + (k -> (map(k) |+| v))
}
}
}
[...]
Agora, para a sua pergunta, não há necessidade de alterar mergeKeys
para lidar com
engraçado tipos de combinações;basta escrever um Monoid
para lidar com qualquer tipo de
a combinação que você deseja fazer.Digamos que você queira fazer suas Seqüências+Ints exemplo:
implicit def monoidStringInt = new Monoid[(String, Int)] {
val zero = ("", 0)
def append(a: (String, Int), b: => (String, Int)) = (a, b) match {
case ((a1, a2), (b1, b2)) => (a1 + b1, a2 + b2)
}
}
println {
List(
"a" -> ("Hello, ", 20),
"b" -> ("Goodbye, ", 30),
"a" -> ("World", 12)
).mergeKeys
}
dá
Map(a -> (Hello, World,32), b -> (Goodbye, ,30))