Scala - max函数返回错误结果

时间:2014-01-26 19:33:40

标签: scala

下面给出的max函数返回列表的最后一个元素的最后一个值,而不是最大值(我为调试目的添加了一些额外的println

def max(xs: List[Int]): Int = {
  def loop(largest: Int, ys: List[Int]): Int = {
    println("ys: " + ys)
    println("largest: " + largest)
    if(!ys.isEmpty) {
      println("ys.head: " + ys.head + "\n")
      if (largest >= ys.head)
        loop(largest, ys.tail)
      else ys.head
        loop(ys.head, ys.tail)
    }
    else largest
  }
  loop(xs.head, xs.tail)
}

scala> max(List(1,2,3,1,2))

的控制台输出
ys: List(2, 3, 1, 2)
largest: 1
ys.head: 2

ys: List(3, 1, 2)
largest: 2
ys.head: 3

ys: List(1, 2)
largest: 3
ys.head: 1

ys: List(2)
largest: 3
ys.head: 2

ys: List()
largest: 3 // shouldn't it just end here?
ys: List()
largest: 2
ys: List(2)
largest: 1
ys.head: 2

ys: List()
largest: 2
res0: Int = 2

3 个答案:

答案 0 :(得分:2)

您的if表达式应为:

if (largest >= ys.head)
    loop(largest, ys.tail)
else
    loop(ys.head, ys.tail)

您的代码目前与以下内容相同:

val result = if (largest >= ys.head)
                 loop(largest, ys.tail)
             else ys.head

loop(ys.head, ys.tail)

所以你丢弃了递归调用的结果,然后返回loop(ys.head, ys.tail)

答案 1 :(得分:2)

仔细看看else部分的外观:

else ys.head
  loop(ys.head, ys.tail)

它没有多大意义:)这个应该是正确的:

else loop(ys.head, ys.tail)

但在这种情况下,我宁愿使用模式匹配:

def max(xs: List[Int]): Int = {
  def loop(largest: Int, ys: List[Int]): Int = ys match {
    case y :: rest if y > largest => loop(y, rest)
    case y :: rest => loop(largest, rest)
    case _ => largest
  }

  loop(xs.head, xs.tail)
}

我发现它更易于阅读和分析,并且(可以说)它会使得更难以犯这种错误

答案 2 :(得分:0)

获取列表最大值的众多方法之一依赖于对列表进行排序,然后获取第一个(或最后一个)元素;例如

def max(xs: List[Int]): Int = (xs sortWith {_>_}) (0)

在此函数中,sortWith可以替换为对QuickSort实现的调用。

查看https://jazzy.id.au/default/2012/10/16/benchmarking_scala_against_java.html,了解QuickSort的非惯用Scala实现,并针对Java和惯用方法进行基准测试。