在R中跳出嵌套循环

10

非常简单的示例代码(仅用于演示,没有任何用处):

repeat {
  while (1 > 0) {
    for (i in seq(1, 100)) {
      break # usually tied to a condition
    }
    break
  }
  break
}
print("finished")

我希望在不使用每个循环中的break的情况下从多个循环中退出。根据关于Python的类似问题的这篇文章,将我的循环包装成一个函数似乎是一个可能的解决方案,即在函数中使用return()来跳出每个循环:

nestedLoop <- function() {
  repeat {
    while (1 > 0) {
      for (i in seq(1, 100)) {
        return()
      }
    }
  }
}

nestedLoop()
print("finished")

在R中有其他可用的方法吗?也许类似于标记循环然后指定要中断哪个循环(就像Java中那样)的方法?


2
我不知道其他的方法,会像这样使用return。但是当然,我已经好几个月没有编写嵌套的 R 循环了,也有好几年没有使用 R 的 whilerepeat 循环了。 - Roland
将循环封装为函数的问题在于,如果需要在代码的其他位置使用循环内部生成的大型变量列表,则可能必须从循环内部返回这些变量到全局环境。 - Robomatix
不,你的问题在于使用了太多循环。高效的 R 代码很少使用嵌套循环。 - Roland
我们不是在谈论将性能推向极限,而是在讨论时间方面的数量级。 - Roland
我认为你想要“返回”“某些东西”。 - IRTFM
2个回答

19

使用显式标志,并在循环条件受到这些标志的限制时退出循环,可以使人更加灵活。例如:

stop = FALSE
for (i in c(1,2,3,4)){
    for (j in c(7,8,9)){
        print(i)
        print(j)
        if (i==3){
            stop = TRUE # Fire the flag, and break the inner loop
            break
        }
        }
    if (stop){break} # Break the outer loop when the flag is fired
    }

i=3时,上述代码将中断两个嵌套的循环。当注释掉最后一行(if (stop){break})时,只有内部循环在i=3时被中断,但外部循环继续运行,也就是实际上跳过了i=3的情况。该结构易于操作,并且可以根据需要灵活调整。


6

我认为将嵌套循环封装成函数的方法是最干净、最好的方法。在全局环境中,您实际上可以调用return(),但它会抛出错误并且看起来不美观,如下所示:

for (i in 1:10) {
  for (a in 1:10) {
    for(b in 1:10) {

      if (i == 5 & a == 7 & b == 2) { return() }

    }
  }
}

print(i)
print(a)
print(b)

在命令行中,它的显示如下:
> for (i in 1:10) {
+   for (a in 1:10) {
+     for(b in 1:10) {
+       
+       if (i == 5 & a == 7 & b == 2) { return() }
+       
+     }
+   }
+ }
Error: no function to return from, jumping to top level
> 
> print(i)
[1] 5
> print(a)
[1] 7
> print(b)
[1] 2

显然最好和更干净的方法是使用函数方式。

编辑:

添加了Roland提供的使错误信息更美观的替代方案:

for (i in 1:10) {
  for (a in 1:10) {
    for(b in 1:10) {

      if (i == 5 & a == 7 & b == 2) { stop("Let's break out!") }

    }
  }
}

print(i)
print(a)
print(b)

好的,你可以直接使用 simpleError 抛出错误。 - Roland
return() 替换为 simpleError("", call = return()) 仍然会在控制台中抛出错误,尽管我以前没有见过 simpleError,所以可能使用不正确。 - giraffehere
尝试使用 stop("让我们退出!"),它会返回一个 simpleError 对象。 - Roland
在另一个版本中添加,这是你的意思吗? - giraffehere
1
是的,这比仅因想要一个错误而使用会抛出错误的表达式/函数要好。当然,这仍然不是一个好的解决方案,因为这不是错误的适当用法。如果将此代码放入函数中,您将会明白原因。从该函数中无法得到返回值。 - Roland
是的,我同意将其包装在一个函数中是实现 OP 想要的正确方法。只是为了尝试而已。 - giraffehere

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接