2013-04-12 22 views
7

我写了一个名为reduceByKey简单的函数,它的(键,数字)对,并返回键减少收集收集任何类型。斯卡拉reduceByKey功能 - 使用具有+方法

def reduceByKey[K](collection: Traversable[Tuple2[K, Int]]) = {  
    collection 
     .groupBy(_._1) 
     .map { case (group: K, traversable) => traversable.reduce{(a,b) => (a._1, a._2 + b._2)} } 
    } 

这当前适用于:

scala> val col = List((("some","key"),100), (("some","key"),100), (("some","other","key"),50)) 
col: List[(Product with Serializable, Int)] = List(((some,key),100), ((some,key),100), ((some,other,key),50)) 

scala> reduceByKey(col)  
res42: scala.collection.immutable.Map[Product with Serializable,Int] = Map((some,key) -> 200, (some,other,key) -> 50) 

但是,我只要我想用非int类型的数字,它悲惨的失败了,因为它期望的Int

scala> val col = List((("some","key"),100.toDouble), (("some","key"),100.toDouble), (("some","other","key"),50.toDouble)) 
col: List[(Product with Serializable, Double)] = List(((some,key),100.0), ((some,key),100.0), ((some,other,key),50.0)) 

scala> reduceByKey(col) 
<console>:13: error: type mismatch; 
found : List[(Product with Serializable, Double)] 
required: Traversable[(?, Int)] 
       reduceByKey(col) 
           ^

当然,我可以针对不同的类型制作不同的方法,但这很愚蠢。基本上我希望我的方法可以使用定义了+方法的任何类型。这将是DoubleFloatLongIntShort

  1. 起初,我想我可以使用结构类型而不是Int。但这意味着结构类型需要引用自身以便用于任何用途。
  2. 我看着Numeric我认为可能有用的特质。它封装了所有数字类型的+方法。但是,我不确定如何在我的情况下使用它。我不想强制我的函数的用户在Numeric中包装值,只是为了让我的函数工作。函数本身应该以某种方式隐含地包装它并调用Numeric.plus

我愿意接受任何建议,如何解决这个问题。

+1

这是一个答案,但如此简洁不应该被提出这样:使用类型类。其他人可能会很快提供详细信息。如果不是,我会尽力让时间。 –

回答

15

如果你只对数值有兴趣,你可以使用标准的Numeric型类和做到这一点:

def reduceByKey[K,V](collection: Traversable[Tuple2[K, V]])(implicit num: Numeric[V]) = {  
    import num._ 
    collection 
    .groupBy(_._1) 
    .map { case (group: K, traversable) => traversable.reduce{(a,b) => (a._1, a._2 + b._2)} } 
} 

num隐含参数用作证据V是数值型,并提供+这种类型的操作。