스칼라에서 루프를 끊으려면 어떻게해야합니까?
루프를 해제하려면 어떻게해야합니까?
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 http://www.slideshare.net/Odersky/fosdem-2009-1013261의 Scala Talk에서 22 페이지 :
스칼라는 휴식과 계속하지 않습니다. 왜? 그것들은 약간 필수적입니다. 더 작은 함수를 더 잘 사용하십시오. 클로저와 상호 작용하는 방법을 발행하십시오. 그들은 필요하지 않습니다!
설명은 무엇입니까?
루프에서 벗어날 수있는 세 가지 옵션이 있습니다.
합계가 1000보다 클 때까지 숫자를 합산한다고 가정합니다.
var sum = 0
for (i <- 0 to 1000) sum += i
때를 중지하려는 경우를 제외하고 (sum> 1000).
무엇을해야합니까? 몇 가지 옵션이 있습니다.
(1a) 테스트하는 조건을 포함하는 일부 구문을 사용하십시오.
var sum = 0
(0 to 1000).iterator.takeWhile(_ => sum < 1000).foreach(i => sum+=i)
(경고-이것은 평가하는 동안 takeWhile 테스트와 foreach가 어떻게 인터리브되는지에 대한 세부 사항에 달려 있으며 아마도 실제로 사용해서는 안됩니다!).
(1b) 스칼라에서 새로운 메소드를 작성하는 것이 얼마나 쉬운 지 활용하여 for 루프 대신 테일 재귀를 사용하십시오.
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) 예외를 던지십시오.
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"문을 간과하거나, 실제보다 더 많거나 적은 것을 벗어나거나 할 수없는 두 개의 루프를 끊어야한다고 생각하기 쉽습니다. 어쨌든 쉽게-표준 사용법은 편리하지만 문제가 있으므로 코드를 다른 방식으로 구성해야합니다. 둘째, 스칼라에는 아마 눈치 채지 못하는 모든 종류의 중첩이 있습니다. 따라서 문제가 발생하면 코드 흐름이 끝나는 곳 (특히 폐쇄)에 놀랄 것입니다. 셋째, 스칼라의 "루프"대부분은 실제로 일반적인 루프가 아니며, 자체 루프가있는 메소드 호출입니다.루프와 유사하게 "중단"등이 무엇을해야하는지 알 수있는 일관된 방법을 찾기는 어렵습니다. 따라서 일관성을 유지하기 위해 더 현명한 것은 "중단"하지 않는 것입니다.
참고 : 값을 sum
변경하지 않고 값을 반환하는 모든 기능과 동등한 기능이 있습니다 . 이것들은 더 관용 스칼라입니다. 그러나 논리는 동일하게 유지됩니다. ( return
해진다 return x
등).
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
}
}
}
for-loop를 벗어나는 것은 좋은 생각이 아닙니다. for-loop를 사용하는 경우 반복하려는 횟수를 알고 있음을 의미합니다. 2 가지 조건의 while 루프를 사용하십시오.
예를 들어
var done = false
while (i <= length && !done) {
if (sum > 1000) {
done = true
}
}
다른 방법으로 렉스 커를 추가하려면 :
(1c) 루프에서 가드를 사용할 수도 있습니다.
var sum = 0 for (i <- 0 to 1000 ; if sum<1000) sum += i
break
스칼라에는 아직 없기 때문에-문 을 사용 하여이 문제를 해결할 수 return
있습니다. 따라서 내부 루프를 함수에 넣어야합니다. 그렇지 않으면 리턴이 전체 루프를 건너 뜁니다.
스칼라 2.8은 그러나 깨는 방법을 포함
http://www.scala-lang.org/api/rc/scala/util/control/Breaks.html
// import following package
import scala.util.control._
// create a Breaks object as follows
val loop = new Breaks;
// Keep the loop inside breakable as follows
loop.breakable{
// Loop will go here
for(...){
....
// Break will go here
loop.break;
}
}
브레이크 모듈 사용 http://www.tutorialspoint.com/scala/scala_break_statement.htm
while 루프를 사용하십시오.
var (i, sum) = (0, 0)
while (sum < 1000) {
sum += i
i += 1
}
먼저 전체 범위를 생성 한 다음을 사용하여 반복하는 대신 범위를 넘어서 최대 범위까지 값을 생성하는 접근 방식은 Iterator
(@RexKerr의 사용에서 영감을 얻음 Stream
)
var sum = 0
for ( i <- Iterator.from(1).takeWhile( _ => sum < 1000) ) sum += i
다음은 꼬리 재귀 버전입니다. 사전 이해와 비교할 때 약간 비밀 스럽지만 인정할 만합니다. :)
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 함수는 외부 이해력의 대응 요소이고 내부 함수의 tr1입니다. 내 버전을 최적화하는 방법을 알고 있다면 환영합니다.
솔루션에 가까운 것은 다음과 같습니다.
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-iteration은 새로운 범위없이 이루어지며 제품 생성 및 조건은 for-statement에서 수행됩니다 (좋은 표현이 아닙니다-더 나은 것을 찾지 못합니다). 조건은 그 문제 크기에 대해 매우 빠릅니다. 더 큰 루프에서 휴식을 취할 수 있습니다.
String.reverse는 암시 적으로 RichString으로 변환되므로 2 가지 추가 반전을 수행하는 이유입니다. :) 더 수학적 접근 방식이 더 우아 할 수 있습니다.
타사 breakable
패키지는 하나의 가능한 대안입니다.
https://github.com/erikerlandson/breakable
예제 코드 :
scala> import com.manyangled.breakable._
import com.manyangled.breakable._
scala> val bkb2 = for {
| (x, xLab) <- Stream.from(0).breakable // create breakable sequence with a method
| (y, yLab) <- breakable(Stream.from(0)) // create with a function
| if (x % 2 == 1) continue(xLab) // continue to next in outer "x" loop
| if (y % 2 == 0) continue(yLab) // continue to next in inner "y" loop
| if (x > 10) break(xLab) // break the outer "x" loop
| if (y > x) break(yLab) // break the inner "y" loop
| } yield (x, y)
bkb2: com.manyangled.breakable.Breakable[(Int, Int)] = com.manyangled.breakable.Breakable@34dc53d2
scala> bkb2.toVector
res0: Vector[(Int, Int)] = Vector((2,1), (4,1), (4,3), (6,1), (6,3), (6,5), (8,1), (8,3), (8,5), (8,7), (10,1), (10,3), (10,5), (10,7), (10,9))
스칼라에서 할 수있는 것은
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
아이러니하게도 스칼라 침입 scala.util.control.Breaks
은 예외입니다.
def break(): Nothing = { throw breakException }
가장 좋은 조언은 : 휴식을 취하지 말고 계속 진행하십시오! IMO는 모든 종류의 문제 (그리고 뜨거운 토론)의 동일하고 나쁜 습관과 악의적 근원이며 마지막으로 "유해한 것으로 간주됩니다". 이 예제에서도 코드 블록 구조가 불필요합니다. 우리의 Edsger W. Dijkstra †는 다음과 같이 썼습니다 :
프로그래머의 품질은 그들이 생산하는 프로그램의 진술에 대한 밀도의 감소 기능입니다.
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)
아래는 간단한 방법으로 루프를 끊는 코드입니다
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"
}
}
}
}
}
지난 9 년 동안 스칼라 스타일이 얼마나 많이 바뀌 었는지 모르겠지만, 기존 답변의 대부분이를 사용 vars
하거나 재귀를 읽기 어렵다는 것이 흥미로 웠습니다 . 조기 종료의 핵심은 지연 수집을 사용하여 가능한 후보를 생성 한 다음 조건을 개별적으로 확인하는 것입니다. 제품을 생성하려면 다음을 수행하십시오.
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
만 루프에서 훨씬 나중에 나타납니다.
어쨌든, 분리 된 게으른 생성 및 조건 확인의 장점은 전체 목록을 사용하는 것처럼 거의 작성하지만 필요한만큼만 생성한다는 것입니다. 당신은 두 세계의 최고를 얻을 수 있습니다.
아래 코드와 같은 상황이 있습니다.
for(id<-0 to 99) {
try {
var symbol = ctx.read("$.stocks[" + id + "].symbol").toString
var name = ctx.read("$.stocks[" + id + "].name").toString
stocklist(symbol) = name
}catch {
case ex: com.jayway.jsonpath.PathNotFoundException=>{break}
}
}
Java lib를 사용하고 있으며 메커니즘은 ctx.read가 아무것도 찾을 수 없을 때 예외를 throw한다는 것입니다. 나는 예외가 발생했을 때 루프를 끊어야하지만 scala.util.control.Breaks.break는 예외를 사용하여 루프를 끊고 catch 블록에 있었기 때문에 잡혔습니다.
나는 이것을 해결하기위한 추악한 방법을 얻었다 : 처음으로 루프를 수행하고 실제 길이의 수를 얻는다. 두 번째 루프에 사용하십시오.
자바 라이브러리를 사용할 때 스칼라에서 휴식을 취하는 것은 그리 좋지 않습니다.
나는 스칼라를 처음 사용하지만 예외가 발생하고 반복되는 방법을 피하기 위해 어떻습니까?
object awhile {
def apply(condition: () => Boolean, action: () => breakwhen): Unit = {
while (condition()) {
action() match {
case breakwhen(true) => return ;
case _ => { };
}
}
}
case class breakwhen(break:Boolean);
다음과 같이 사용하십시오.
var i = 0
awhile(() => i < 20, () => {
i = i + 1
breakwhen(i == 5)
});
println(i)
중단하고 싶지 않은 경우 :
awhile(() => i < 20, () => {
i = i + 1
breakwhen(false)
});
import scala.util.control._
object demo_brk_963
{
def main(args: Array[String])
{
var a = 0;
var b = 0;
val numList1 = List(1,2,3,4,5,6,7,8,9,10);
val numList2 = List(11,12,13);
val outer = new Breaks; //object for break
val inner = new Breaks; //object for break
outer.breakable // Outer Block
{
for( a <- numList1)
{
println( "Value of a: " + a);
inner.breakable // Inner Block
{
for( b <- numList2)
{
println( "Value of b: " + b);
if( b == 12 )
{
println( "break-INNER;");
inner.break;
}
}
} // inner breakable
if( a == 6 )
{
println( "break-OUTER;");
outer.break;
}
}
} // outer breakable.
}
}
Breaks 클래스를 사용하여 루프를 끊는 기본 방법. 루프를 파괴 가능하다고 선언함으로써.
참고 URL : https://stackoverflow.com/questions/2742719/how-do-i-break-out-of-a-loop-in-scala
'IT' 카테고리의 다른 글
WiX 트릭과 팁 (0) | 2020.03.29 |
---|---|
C #에서 필드를 '읽기 전용'으로 표시하면 어떤 이점이 있습니까? (0) | 2020.03.29 |
데이터를 복사하지 않고 Oracle 테이블의 복사본을 만들려면 어떻게해야합니까? (0) | 2020.03.29 |
Sublime Text 3의 80 자 / 오른쪽 여백 줄 (0) | 2020.03.29 |
표 셀의 텍스트가 줄 바꿈되지 않도록하는 방법 (0) | 2020.03.29 |