我如何打破一个循环?

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没有它们。为什么? 它们有点迫不得已;最好使用许多较小的函数 发布如何与闭包交互。 他们是不需要的!

怎么解释呢?


当前回答

在scala中我们能做的就是

scala> import util.control.Breaks._

scala> object TestBreak {
       def main(args : Array[String]) {
         breakable {
           for (i <- 1 to 10) {
             println(i)
             if (i == 5)
               break;
       } } } }

输出:

scala> TestBreak.main(Array())
1
2
3
4
5

其他回答

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

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

在scala中我们能做的就是

scala> import util.control.Breaks._

scala> object TestBreak {
       def main(args : Array[String]) {
         breakable {
           for (i <- 1 to 10) {
             println(i)
             if (i == 5)
               break;
       } } } }

输出:

scala> TestBreak.main(Array())
1
2
3
4
5

这是一个尾部递归的版本。不可否认,与for推导式相比,它有点晦涩,但我认为它是功能性的:)

def run(start:Int) = {
  @tailrec
  def tr(i:Int, largest:Int):Int = tr1(i, i, largest) match {
    case x if i > 1 => tr(i-1, x)
    case _ => largest
  }

  @tailrec
  def tr1(i:Int,j:Int, largest:Int):Int = i*j match {
    case x if x < largest || j < 2 => largest
    case x if x.toString.equals(x.toString.reverse) => tr1(i, j-1, x)
    case _ => tr1(i, j-1, largest)
  }

  tr(start, 0)
}

如您所见,tr函数是外部for推导式的对应函数,tr1是内部for推导式的对应函数。如果你知道如何优化我的版本,欢迎你。

下面是用简单的方式打破循环的代码

import scala.util.control.Breaks.break

object RecurringCharacter {
  def main(args: Array[String]) {
    val str = "nileshshinde";

    for (i <- 0 to str.length() - 1) {
      for (j <- i + 1 to str.length() - 1) {

        if (str(i) == str(j)) {
          println("First Repeted Character " + str(i))
          break()     //break method will exit the loop with an Exception "Exception in thread "main" scala.util.control.BreakControl"

        }
      }
    }
  }
}

我不知道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,但在循环中出现得更晚。

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