我试图编写一个返回值列表中最接近的值的算法。所以在List(4.0,6.0,2.0)中,最接近7.0的值是6.0
以下是我使用的代码,但由于返回的最接近的值为4,因此不正确:
如何解决以下代码或是否有可用于解决此问题的Scala实用程序方法?
val num = 7.0 //> num : Double = 7.0
val listNums = List[Double](4,6,2) //> listNums : List[Double] = List(4.0, 6.0, 2.0)
def getClosest(num : Double , listNums : List[Double]) = {
var min = java.lang.Double.MAX_VALUE
var closest = num
for(x <- listNums ){
val diff = x - num
if(num < min){
min = diff
closest = x
}
}
closest
} //> getClosest: (num: Double, listNums: List[Double])Double
val closest = getClosest(num , listNums) //> closest : Double = 4.0
答案 0 :(得分:16)
这几乎是一行minBy
:
def getClosest(num: Double, listNums: List[Double]) =
listNums.minBy(v => math.abs(v - num))
不幸的是, minBy
是部分函数 - 当在空列表中调用时,它会因异常而崩溃。要匹配实现的行为,可以编写以下内容:
def getClosest(num: Double, listNums: List[Double]) = listNums match {
case Nil => Double.MaxValue
case list => list.minBy(v => math.abs(v - num))
}
您的代码存在的问题是您没有采用绝对值,因为另一个答案暗示指出。不要使用Math.abs
,这是java.lang.Math.abs
的简写。 math.abs
更具惯用性。
答案 1 :(得分:3)
一个简单的实现是:
def getClosest(num : Double , list : List[Double]) :Double = list match {
case x :: xs => list.foldLeft(x){(ans,next) =>
if(math.abs(next - num) < math.abs(ans - num)) next else ans }
case Nil => throw new RuntimeException("Empty list")
}
scala> getClosest(20, List(1,19,22,24))
res0: Double = 19.0
更通用的实施方式是:
def getClosest[A: Numeric](num: A, list: List[A]): A = {
val im = implicitly[Numeric[A]]
list match {
case x :: xs => list.minBy (y => im.abs(im.minus(y, num)))
case Nil => throw new RuntimeException("Empty list")
}
}
感谢@Travis建议minBy
。它比foldLeft
答案 2 :(得分:0)
答案 3 :(得分:0)
如果您想要更通用,可以试试这个:
def getClosest[A: Numeric](value: A, elems: Traversable[A]): A = {
val ops = implicitly[Numeric[A]]
elems.minBy(e => ops.abs(ops.minus(e, value)))
}
然后:
getClosest(20, List(1, 19, 22, 24))
//> res1: Int = 19
getClosest(BigDecimal("5000000000000000"), List(BigDecimal(1), BigDecimal(19)))
//> res2: scala.math.BigDecimal = 19