我是scala的新手,为了练习,我尝试编写一个通用函数来计算整数或双精度数的中位数。 下面是代码片段:
implicit class trial[T](seq: Seq[T]) {
def median[T](implicit num: Fractional[T]):Double = {
import num._
seq.sorted match {
case x if x.length % 2 != 0 => x(x.length / 2).toDouble()
case x => (x(x.length / 2).toDouble() + x(x.length / 2 - 1).toDouble()) / 2
}
}
}
在上面的代码中,排序功能不起作用,表示找不到隐式排序。有人可以指导我如何在scala中对数字列表进行排序吗?
编辑==>
查看完这篇文章的答案后,我已经更改了代码(更改后的代码粘贴在下面),现在它适用于Ints和Doubles,但是现在如果将来如果我必须支持BigDecimals,那么我将必须进行哪些更改做吗?
implicit class GenericMedian[T](seq: Seq[T]) {
def median(implicit num: Numeric[T]) = {
import num._
val medianPosition = seq.length / 2
seq.sortWith(num.gt) match {
case x if x.length % 2 != 0 => x(medianPosition)
case x => (x(medianPosition).toDouble() + x(medianPosition - 1).toDouble()) / 2
}
}
}
答案 0 :(得分:1)
这对我来说适用于 Scala 2.13
implicit class trial[T](private val seq: Seq[T]) extends AnyVal {
def median(implicit num: Integral[T]): T = {
import num._
val sorted = seq.sorted
val length = sorted.length
val medianPosition = length / 2
if ((length % 2) == 0)
sorted(medianPosition)
else
(sorted(medianPosition) + sorted(medianPosition + 1)) / num.fromInt(2)
}
}
我忘了提到您的代码(至少在编译方面)的唯一真正问题是,因为您要在代码的定义中定义一个新的T
类型变量方法。您不能使用该隐式对序列进行排序,因为对于编译器而言,它们是两种不同的类型。
答案 1 :(得分:1)
以下使用Numeric
类型类来处理整数和双精度数
implicit class MedianSeq[T](seq: Seq[T]) {
def median(implicit num: Numeric[T]): Option[Double] = {
val sorted = seq.sorted
val fractionalMidpoint: Double = sorted.size / 2.0
sorted.size match {
case x if x < 2 => None
case x if x == 2 => Some(num.toDouble(num.plus(seq(0), seq(1))) / 2)
case x =>
if (fractionalMidpoint % 2 != 0.0) {
Some(num.toDouble(sorted(fractionalMidpoint.toInt)))
} else {
val a = sorted(fractionalMidpoint.toInt - 1)
val b = sorted(fractionalMidpoint.toInt)
Some(num.toDouble(num.plus(a, b)) / 2)
}
}
}
}
输出
Seq(3,5,2,34,5,6,7,87,8).median == Some(6.0) // true
Seq(1,2,3,4).median == Some(2.5) // true
Seq(1.0,2.0,3.0,4.0).median == Some(2.5) // true
Seq(1,2).median == Some(1.5) // true
Seq(1,1).median == Some(1.0) // true
Seq(1).median == None // true
请注意,当元素数为偶数时,我们使用this中位数的定义:
当有两个中间数字时,我们将它们取平均值。
因此Seq(1,2).median == Some(1.5)