2013-04-12 30 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是數值型,並提供+這種類型的操作。