Scala中如何用函数式方法计算点列表的周长?
嘿,我来帮你解决这个Scala的类型不匹配问题!
首先得搞清楚为啥你用reduceLeft(euclideanDist)会报错:reduceLeft的工作逻辑是,拿前一次运算的结果和下一个列表元素继续执行传入的函数。第一次调用euclideanDist会得到一个Double值,但下一次它就会尝试把这个Double和下一个List[Double]传给euclideanDist——可你的函数只接受两个List[Double]参数啊!这就直接触发了类型不匹配的编译错误。
不用命令式循环,咱们用Scala地道的函数式写法来搞定,这里有两种靠谱的方案:
方案1:用sliding(2)生成连续点对
sliding(2)方法可以把你的点列表分割成连续的两两子序列,比如你的输入会被拆成(List(0,0), List(0,1))、(List(0,1), List(1,1))这样的点对,接着对每个点对计算距离,最后求和就行:
import scala.collection.mutable.ListBuffer import math.{sqrt, pow} // 你的欧氏距离函数保持不变 def euclideanDist(pt1: List[Double], pt2: List[Double]): Double = sqrt(pow(pt1(0)-pt2(0), 2) + pow(pt1(1)-pt2(1), 2)) def perimeter(arr: ListBuffer[List[Double]]): Double = arr.sliding(2) .map { case List(pt1, pt2) => euclideanDist(pt1, pt2) } .sum
测试一下你的示例输入:
val arr: ListBuffer[List[Double]] = ListBuffer(List(0, 0), List(0,1), List(1,1), List(1,0), List(0, 0)) perimeter(arr) // 输出 4.0,完全符合预期
方案2:用foldLeft追踪前一个点和总和
如果想更明确地控制遍历过程,可以用foldLeft来携带两个状态:遍历到当前的总和,以及前一个点。这样每次迭代都能计算当前点和前一个点的距离,并累加到总和里:
def perimeter(arr: ListBuffer[List[Double]]): Double = arr.tail.foldLeft((arr.head, 0.0)) { case ((prevPt, total), currPt) => (currPt, total + euclideanDist(prevPt, currPt)) }._2
这里arr.tail从第二个点开始遍历,初始状态是(第一个点, 0.0),每次迭代更新当前点和总和,最后取出元组的第二个元素就是周长总和。
这两种写法都是纯函数式的,完全符合Scala的风格,而且完美解决了类型不匹配的问题~
内容的提问来源于stack exchange,提问作者Ébe Isaac
相关产品推荐
相关产品推荐

