在Scala中编写通用均值函数

时间:2011-05-31 14:20:54

标签: 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))

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

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

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

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

4 个答案:

答案 0 :(得分: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!")
}

所以,让我们做一些解释。首先,必须在类型类模式中使用Numeric。也就是说,您没有说T类型,或者可以转换为Numeric。相反,Numeric提供了类型T上的方法。其中一个例子是num.fromInt

接下来,Numeric不提供公共除法运算符。相反,必须在FractionalIntegral之间进行选择。在这里,我匹配Numeric[T]以区分两者。

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

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

num.div(xs.sum, num.fromInt(xs.size))

请注意,我不必将隐式参数传递给xs.sum,因为它已在范围内隐式提供。

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

答案 1 :(得分:7)

你的一个版本非常接近:

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

以下是其他语法:

def mean[T: Numeric](xs: Iterable[T]):Double =
  implicitly[Numeric[T]].toDouble(xs.sum) / xs.size

答案 2 :(得分:4)

def mean[A](it:Iterable[A])(implicit n:Numeric[A]) = {
  it.map(n.toDouble).sum / it.size
}

答案 3 :(得分:0)

这是一个很老的问题,但我基本上是在做这个

def average[A](list: List[Any])(implicit numerics: Numeric[A]): Double = {
  list.map(Option(_)).filter(_.isDefined).flatten match {
    case Nil => 0.0
    case definedElements => numerics.toDouble(list.map(_.asInstanceOf[A]).sum) / definedElements.length.toDouble
  }
}

表示可能包含null值的列表(我必须保持与Java的互操作性)。 null元素不计入平均值。