Как я вспыхиваю цикл?
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
}
}
Как я становлюсь вложенным для циклов в хвостовую рекурсию?
От Разговора Scala по http://www.slideshare.net/Odersky/fosdem-2009-1013261 2009 года FOSDEM на 22-й странице:
Повредитесь и продолжите, у Scala нет их. Почему? Они немного обязательны; лучше используйте много меньших Проблем функций, как взаимодействовать с закрытиями. Они не нужны!
Каково объяснение?
У вас есть три (или около того) варианта выхода из петель.
Предположим, вы хотите суммировать числа, пока общая сумма не превысит 1000. Вы пробуете
var sum = 0
for (i <- 0 to 1000) sum += i
, но хотите остановиться, когда (сумма> 1000).
Что делать? Есть несколько вариантов.
(1a) Используйте некоторую конструкцию, включающую тестируемое вами условие.
var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)
(предупреждение - это зависит от деталей того, как тест takeWhile и foreach чередуются во время оценки, и, вероятно, не должны использоваться на практике!).
(1b) Используйте хвостовую рекурсию вместо цикла for, воспользовавшись тем, насколько легко написать новый метод в Scala:
var sum = 0
def addTo(i: Int, max: Int) {
sum += i; if (sum < max) addTo(i+1,max)
}
addTo(0,1000)
(1c) Вернуться к использованию цикла while
var sum = 0
var i = 0
while (i <= 1000 && sum <= 1000) { sum += 1; i += 1 }
(2) Throw исключение.
object AllDone extends Exception { }
var sum = 0
try {
for (i <- 0 to 1000) { sum += i; if (sum>=1000) throw AllDone }
} catch {
case AllDone =>
}
(2a) В Scala 2.8+ это уже предварительно упаковано в scala.util.control.Breaks
с использованием синтаксиса, который очень похож на вашу знакомую старую паузу от C / Java:
import scala.util.control.Breaks._
var sum = 0
breakable { for (i <- 0 to 1000) {
sum += i
if (sum >= 1000) break
} }
( 3) Поместите код в метод и используйте return.
var sum = 0
def findSum { for (i <- 0 to 1000) { sum += i; if (sum>=1000) return } }
findSum
Это намеренно сделано не слишком легко, по крайней мере, по трем причинам, о которых я могу думать. Во-первых, в больших блоках кода легко упустить из виду операторы continue и break, или подумать, что вы выходите из большего или меньшего количества, чем вы есть на самом деле, или вам нужно разорвать два цикла, которые вы не можете сделать. в любом случае легко - поэтому стандартное использование, хотя и удобное, имеет свои проблемы, и поэтому вы должны попытаться структурировать свой код по-другому. Во-вторых, в Scala есть всевозможные вложенности, которые вы, вероятно, даже не замечаете, поэтому, если бы вы могли вырваться из чего-то, вы, вероятно, были бы удивлены тем, где закончился поток кода (особенно с замыканиями).В-третьих, большинство «циклов» Scala на самом деле не являются обычными циклами - это вызовы методов, у которых есть собственный цикл, или они являются рекурсией, которая может быть, а может и не быть циклом - и хотя они действуют , и трудно придумать последовательный способ узнать, что делать «break» и тому подобное. Итак, чтобы быть последовательным, разумнее вообще не делать «перерыв».
Примечание : Существуют функциональные эквиваленты всего этого, в которых вы возвращаете значение sum
, а не изменяете его на месте. Это более идиоматическая Scala. Однако логика осталась прежней. ( return
становится return x
и т. Д.).
Поскольку в Scala пока нет break
, вы можете попытаться решить эту проблему с помощью return
-статей. Поэтому внутренний цикл нужно поместить в функцию, иначе return пропустит весь цикл.
Scala 2.8, однако, включает способ нарушить
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
Чтобы добавить Рекса Керра, ответьте другим способом:
(1c) Вы также можете использовать защиту в своем цикле:
var sum = 0 {{1} } для (i <- от 0 до 1000; если сумма <1000) sum + = i
Близким к вашему решению было бы следующее:
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 ( нехорошее выражение - лучше не нахожу). Условие меняется на обратное, что довольно быстро для такого размера задачи - возможно, вы получите что-то с перерывом для больших циклов.
String.reverse неявно преобразуется в RichString, поэтому я делаю 2 дополнительных реверса. :) Более математический подход мог бы быть более элегантным.