Scala reduceByKey 函数 - 使用任何具有 + 方法的类型 [英] Scala reduceByKey function - use any type that has + method
问题描述
我正在编写一个名为 reduceByKey
的简单函数,它接受(键、数字)对的集合并逐键返回缩减的集合.
def reduceByKey[K](collection: Traversable[Tuple2[K, Int]]) = {收藏.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))标度>reduceByKey(col)res42:scala.collection.immutable.Map[带序列化的产品,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))标度>reduceByKey(col)<console>:13: 错误:类型不匹配;发现:列表[(具有可序列化的产品,双)]要求:可遍历[(?, Int)]reduceByKey(col)^
当然,我可以为不同的类型制定不同的方法,但这很愚蠢.基本上我希望我的方法适用于任何定义了 +
方法的类型.那将是 Double
、Float
、Long
、Int
和 Short
.>
- 起初,我认为我可以使用结构类型而不是 Int.但这意味着结构类型需要引用自身才能发挥作用.
- 我研究了 Numeric 我认为可能有用的特征.它封装了所有数值类型的 + 方法.但是,我不确定如何在我的情况下使用它.我不想强迫我的函数的用户为了我的函数工作而将值包装在 Numeric 中.函数本身应该以某种方式隐式包装它并调用
Numeric.plus
.
对于如何解决这个问题,我愿意接受任何建议.
如果你只对数值感兴趣,你可以使用标准的 Numeric
类型类并这样做:
def reduceByKey[K,V](collection: Traversable[Tuple2[K, V]])(implicit num: Numeric[V]) = {进口数量._收藏.groupBy(_._1).map { case (group: K, traversable) =>traversable.reduce{(a,b) =>(a._1, a._2 + b._2)} }}
num
隐式参数作为 V
是数字类型的证据,并为该类型提供 +
操作.>
I am writing a simple function called reduceByKey
that takes a collection of (key, numeric) pairs and returns reduced collection by key.
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)} }
}
This currently works for:
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)
But, I as soon as I want to use non-Int type for numeric, it fails miserably, as it expects an 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)
^
Of course, I could make different methods for different types, but that would be silly. Basically I want my method to work with any type that has +
method defined. That would be Double
, Float
, Long
, Int
and Short
.
- At first, I thought I could use structural type instead of Int. But that would mean the structural type would need to reference itself in order to be of any use.
- I looked into Numeric trait that I think could be useful. It encapsulates the + methods of all numeric types. However, I am not sure how to use it in my case. I dont want force the user of my function to wrap values in Numeric just for my function to work. The function itself should somehow implicitly wrap it up and invoke
Numeric.plus
.
I am open to any suggestions as how to solve this.
If you are only interested in numeric values, you can use the standard Numeric
type class and do this:
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)} }
}
The num
implicit parameter serves as an evidence that V
is a numeric type, and provides the +
operation for this type.
这篇关于Scala reduceByKey 函数 - 使用任何具有 + 方法的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!