其他循环构造同时重复

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
}