Функция Scala reduByKey - используйте любой тип, который имеет + метод

Я пишу простую функцию под названием 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,

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

Конечно, я мог бы сделать разные методы для разных типов, но это было бы глупо. В основном я хочу, чтобы мой метод работал с любым типом, который имеет + метод определен. Это было бы Double, Float, Long, Int а также Short,

  1. Сначала я подумал, что мог бы использовать структурный тип вместо Int. Но это будет означать, что структурный тип должен ссылаться на себя, чтобы иметь какое-либо применение.
  2. Я изучил числовую черту, которая, по моему мнению, может быть полезной. Он инкапсулирует методы + всех числовых типов. Тем не менее, я не уверен, как использовать его в моем случае. Я не хочу заставлять пользователя моей функции переносить значения в Numeric только для того, чтобы моя функция работала. Сама функция должна как-то неявно обернуть ее и вызвать Numeric.plus,

Я открыт для любых предложений, как решить эту проблему.

1 ответ

Решение

Если вас интересуют только числовые значения, вы можете использовать стандартные 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 является числовым типом, и обеспечивает + операция для этого типа.

Другие вопросы по тегам