我想编写一个方法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,v)) => map + (k -> (map(k) |+| v)) } } } implicit def superTraversable[T,F[_]]( as: TraversableOnce[(T,F[U])] ): SuperTraversable[T,F] = new SuperTraversable[T,F] { val value = as }
解决方法
首先,虽然它与您的问题无关,但您限制了代码
通过明确提到类型构造函数F [_].它工作正常
没有这样做:
通过明确提到类型构造函数F [_].它工作正常
没有这样做:
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,v)) => map + (k -> (map(k) |+| v)) } } } [...]
现在,对于您的实际问题,没有必要更改mergeKeys来处理
有趣的组合;只需写一个Monoid来处理任何类型的
结合你想做的事.假设你想做你的Strings Ints示例:
implicit def monoidStringInt = new Monoid[(String,Int)] { val zero = ("",0) def append(a: (String,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))