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
    }
Foi útil?

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
}

Map(a -> (Hello, World,32), b -> (Goodbye, ,30))
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top