scala – 使用任何Monoid的键对值进行分组

我想编写一个方法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 [_].它工作正常
没有这样做:

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

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...