其他迴圈構造同時重複

R 提供了兩個額外的迴圈結構 whilerepeat,它們通常用於需要迭代次數不確定的情況。

while 迴圈

while 迴圈的一般形式如下,

while (condition) {
    ## do something
    ## in loop body
}

其中 condition 在進入迴圈體之前進行評估。如果 condition 計算為 TRUE,則迴圈體內的程式碼被執行,並且該過程重複直到 condition 計算為 FALSE(或達到 break 語句;見下文)。與 for 迴圈不同,如果 while 迴圈使用變數執行增量迭代,則必須提前宣告和初始化變數,並且必須在迴圈體內更新。例如,以下迴圈完成相同的任務:

for (i in 0:4) {
    cat(i, "\n")
}
# 0 
# 1 
# 2 
# 3 
# 4 

i <- 0
while (i < 5) {
    cat(i, "\n")
    i <- i + 1
}
# 0 
# 1 
# 2 
# 3 
# 4 

在上面的 while 迴圈中,線 i <- i + 1 是防止無限迴圈所必需的。

另外,可以通過從迴圈體內部呼叫 break 來終止 while 迴圈:

iter <- 0
while (TRUE) {
    if (runif(1) < 0.25) {
        break
    } else {
        iter <- iter + 1
    }
}
iter
#[1] 4

在這個例子中,condition 總是 TRUE,所以終止迴圈的唯一方法是在體內呼叫 break。請注意,iter 的最終值將取決於執行此示例時 PRNG 的狀態,並且每次執行程式碼時(基本上)應產生不同的結果。

repeat 迴圈

repeat 構造與 while (TRUE) { ## something } 基本相同,具有以下形式:

repeat ({
    ## do something
    ## in loop body
})

額外的 {} 不是必需的,但是 () 是。使用 repeat 重寫上一個例子,

iter <- 0
repeat ({
    if (runif(1) < 0.25) {
        break
    } else {
        iter <- iter + 1
    }
})
iter
#[1] 2 

更多關於 break

重要的是要注意 break 只會終止直接封閉的迴圈。也就是說,以下是無限迴圈:

while (TRUE) {
    while (TRUE) {
        cat("inner loop\n")
        break
    }
    cat("outer loop\n")
}

但是,通過一點創造力,可以完全從巢狀迴圈中完全破壞。作為示例,請考慮以下表示式,在其當前狀態下,將無限迴圈:

while (TRUE) {
    cat("outer loop body\n")
    while (TRUE) {
        cat("inner loop body\n")
        x <- runif(1)
        if (x < .3) {
            break
        } else {
            cat(sprintf("x is %.5f\n", x))
        }
    }
}

一種可能性是認識到,與 break 不同,return 表示式確實具有跨多個封閉環迴圈返回控制的能力。但是,由於 return 僅在函式內使用時才有效,我們不能簡單地用 return() 替換 break,而是需要將整個表示式包裝為匿名函式:

(function() {
    while (TRUE) {
        cat("outer loop body\n")
        while (TRUE) {
            cat("inner loop body\n")
            x <- runif(1)
            if (x < .3) {
                return()
            } else {
                cat(sprintf("x is %.5f\n", x))
            }
        }
    }
})()

或者,我們可以在表示式之前建立一個虛擬變數(exit),並在我們準備終止時通過 <<- 從內部迴圈啟用它:

exit <- FALSE
while (TRUE) {
    cat("outer loop body\n")
    while (TRUE) {
        cat("inner loop body\n")
        x <- runif(1)
        if (x < .3) {
            exit <<- TRUE
            break
        } else {
            cat(sprintf("x is %.5f\n", x))
        }
    }
    if (exit) break
}