5

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ただし、のメソッドを記述する代わりに、any を使用できるようにしたいと考えていListます。たとえば、値が整数である可能性があり、それらをリストに追加する代わりに合計したいとします。または(String, Int)、セット内の文字列を蓄積したいが整数を追加したいタプルである可能性があります。どうすればそのようなメソッドを書くことができますか? または、これを行うために scalaz で使用できるものは他にありますか?

更新: 思ったほど遠くありませんでした。私は少し近づいたが、値がタプルである場合にそれを機能させる方法はまだわからない。さらに別の暗黙的な変換を記述する必要がありますか? つまり、型パラメーターの数ごとに 1 つの暗黙的な変換ですか?

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
    }
4

1 に答える 1

6

First, while it's not relevant to your question, you are limiting your code's generality by explicitly mentioning the type constructor F[_]. It works fine without doing so:

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))
        }
    }
}

[...]

Now, for your actual question, there's no need to change mergeKeys to handle funny kinds of combinations; just write a Monoid to handle whatever kind of combining you want to do. Say you wanted to do your Strings+Ints example:

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
}

gives

Map(a -> (Hello, World,32), b -> (Goodbye, ,30))
于 2012-03-15T04:45:26.720 に答える