Reputation: 672
I am trying to implement a generic method to compute the mean of any kind of sequence (for example: List, Array) which contains any kind of numeric values (Int, Float, Double...), like this:
def mean[T <: Numeric[T]](data:Seq[T])(implicit number: Numeric[T]): T = {
data.foldLeft(number.zero)(number.plus) / data.size
}
However, the division operation cannot be resolved. That is because the Numeric type does not have this operation defined (from the ScalaDoc).
I want to convert it to double before proceeding with the division, but the method toDouble(x:T)
from Numeric type expects a param.
I have seen there is a type member for the Numeric[T] called NumericOps
that does implement the toDouble
method without receiving any param. Could I call this method.. somehow?
Upvotes: 2
Views: 412
Reputation: 22840
Here is an example using Fractional, it will preserve the correct precision of the input numbers, and does only one traversal of the data. However, do note that this only works for types that have a "precise" division, like Float
, Double
& BigDecimal
. But does not work for numeric types like Int
or Long
.
def mean[T](data: Iterable[T])(implicit N: Fractional[T]): T = {
import N._
val remaining = data.iterator
@annotation.tailrec
def loop(sum: T, count: Int): T =
if (remaining.hasNext)
loop(sum + remaining.next(), count + 1)
else if (count == 0)
zero
else
sum / fromInt(count)
loop(zero, 0)
}
This was tested on Scala 2.13
.
Upvotes: 4
Reputation: 48400
If Double
precision is sufficient, try
def mean[T](data: Seq[T])(implicit number: Numeric[T]): Double = {
import number._
val sum = data.foldLeft(zero)(plus)
toDouble(sum) / data.size
}
mean(Seq(1,2,3,4)) // 2.5
or using Fractional
(but it will not work for Ints
)
def mean[T](data: Seq[T])(implicit number: Fractional[T]): T = {
import number._
val sum = data.foldLeft(zero)(plus)
div(sum, fromInt(data.size))
}
mean(Seq(1.0,2,3,4)) // 2.5
mean(Seq(1,2,3,4)) // error: could not find implicit value for parameter number: Fractional[Int]
Upvotes: 3
Reputation: 41858
Unless you have to use Numeric
why not just use Fractional
, as that adds a div operation to Numeric
.
You may find this of interest as they talk about the different options:
https://stackoverflow.com/a/40351867/67566
Upvotes: 2