我如何打破一个循环?

var largest=0
for(i<-999 to 1 by -1) {
    for (j<-i to 1 by -1) {
        val product=i*j
        if (largest>product)
            // I want to break out here
        else
           if(product.toString.equals(product.toString.reverse))
              largest=largest max product
    }
}

如何将嵌套for循环转换为尾递归?

来自FOSDEM 2009 Scala Talk http://www.slideshare.net/Odersky/fosdem-2009-1013261 第22页:

中断并继续 Scala没有它们。为什么? 它们有点迫不得已;最好使用许多较小的函数 发布如何与闭包交互。 他们是不需要的!

怎么解释呢?


当前回答

接近你的解决方案是这样的:

var largest = 0
for (i <- 999 to 1 by -1;
  j <- i to 1 by -1;
  product = i * j;
  if (largest <= product && product.toString.reverse.equals (product.toString.reverse.reverse)))
    largest = product

println (largest)

j迭代是在没有新的作用域的情况下进行的,产品生成和条件都是在for语句中完成的(这不是一个好的表达式-我没有找到更好的表达式)。对于这个问题大小来说,条件是反向的,这是相当快的——也许对于更大的循环,您可以通过中断获得一些东西。

字符串。reverse隐式转换为RichString,这就是为什么我做了2个额外的反转。:)一个更数学的方法可能会更优雅。

其他回答

这在Scala 2.8中有所改变,它有一种使用断点的机制。您现在可以执行以下操作:

import scala.util.control.Breaks._
var largest = 0
// pass a function to the breakable method
breakable { 
    for (i<-999 to 1  by -1; j <- i to 1 by -1) {
        val product = i * j
        if (largest > product) {
            break  // BREAK!!
        }
        else if (product.toString.equals(product.toString.reverse)) {
            largest = largest max product
        }
    }
}

再加上雷克斯·科尔的另一种回答:

(1c)你也可以在你的循环中使用守卫: Var和= 0 For (i <- 0到1000;如果sum<1000) sum += I

一种方法,在迭代时在一个范围内生成值,直到中断条件,而不是先生成整个范围,然后使用迭代器在其上迭代,(灵感来自@RexKerr使用Stream)

var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i

巧妙地使用find方法进行收集将为您提供帮助。

var largest = 0
lazy val ij =
  for (i <- 999 to 1 by -1; j <- i to 1 by -1) yield (i, j)

val largest_ij = ij.find { case(i,j) =>
  val product = i * j
  if (product.toString == product.toString.reverse)
    largest = largest max product
  largest > product
}

println(largest_ij.get)
println(largest)

我不知道Scala风格在过去的9年里发生了多大的变化,但我发现一个有趣的现象:大多数现有的答案都使用了var,或者是难以阅读的递归。尽早退出的关键是使用惰性集合生成可能的候选对象,然后分别检查条件。生成产物:

val products = for {
  i <- (999 to 1 by -1).view
  j <- (i to 1 by -1).view
} yield (i*j)

然后在不生成所有组合的情况下从视图中找到第一个回文:

val palindromes = products filter {p => p.toString == p.toString.reverse}
palindromes.head

要找到最大的回文(尽管懒惰不会给你带来什么好处,因为你必须检查整个列表):

palindromes.max

您的原始代码实际上是在检查第一个大于后续产品的回文,这与检查第一个回文是一样的,只是在一个奇怪的边界条件下,我认为这不是您想要的。乘积不是严格单调递减的。例如,998*998大于999*997,但在循环中出现得更晚。

不管怎样,分离的惰性生成和条件检查的优点是,你写它的时候就像使用整个列表一样,但它只生成你需要的东西。你可以说是两全其美了。