在Scala中编写通用均值函数

Bil*_*ear 11 scala

我正在尝试编写一个泛型平均函数,它在包含数字类型的Iterable上运行.例如,它将在数组上运行,如下所示:

val rand = new scala.util.Random()
val a = Array.fill(1000) { rand.nextInt(101) }
val b = Array.fill(1000) { rand.nextDouble }

println(mean(a))
println(mean(b))
Run Code Online (Sandbox Code Playgroud)

希望能够处理其他迭代,例如列表.

我尝试了各种咒语的方法,但无济于事:

def mean[T <% Numeric[T]](xs: Iterable[T]) = xs.sum.toDouble / xs.size
def mean[A](xs: Iterable[Numeric[A]]):Double = xs.sum.toDouble / xs.size
def mean[T](xs: Iterable[T])(implicit num: Numeric[T]):Double = xs.sum / xs.size
def mean(xs: Iterable[Double]) = xs.sum / xs.size
Run Code Online (Sandbox Code Playgroud)

在Scala中执行此操作的正确方法是什么?

Dan*_*ral 17

这有效:

def mean[T : Numeric](xs: Iterable[T]): T = implicitly[Numeric[T]] match {
    case num: Fractional[_] => import num._; xs.sum / fromInt(xs.size)
    case num: Integral[_] => import num._; xs.sum / fromInt(xs.size)
    case _ => sys.error("Undivisable numeric!")
}
Run Code Online (Sandbox Code Playgroud)

那么,让我们做一些解释.首先,Numeric必须在类型类模式中使用.也就是说,你没有说类型T是,或者可以转换成,Numeric.相反,Numeric提供一种类型的方法T.一个这样的例子是num.fromInt.

接下来,Numeric不提供通用的除法运算符.相反,必须在Fractional和之间做出选择Integral.在这里,我匹配Numeric[T]以区分两者.

请注意,我没有T在匹配上使用,因为Scala无法检查匹配上的类型参数,因为它们已被删除.相反,我使用_,如果可能的话,Scala会推断出正确的类型(就像在这里一样).

在那之后,我进口num._,其中num要么是FractionalIntegral.这会将一些隐式转换带入上下文,让我可以/直接调用方法.如果我不做那个导入,我会被迫写这个:

num.div(xs.sum, num.fromInt(xs.size))
Run Code Online (Sandbox Code Playgroud)

请注意,我不必将隐式参数传递给xs.sum,因为它已在范围中隐式可用.

我猜就是这样.我错过了什么吗?


huy*_*hjl 7

你的一个版本非常接近:

def mean[T](xs: Iterable[T])(implicit num: Numeric[T]):Double = 
  num.toDouble(xs.sum) / xs.size
Run Code Online (Sandbox Code Playgroud)

这是另一种语法:

def mean[T: Numeric](xs: Iterable[T]):Double =
  implicitly[Numeric[T]].toDouble(xs.sum) / xs.size
Run Code Online (Sandbox Code Playgroud)