95

我有一个程序可以进行一些数据分析,并且有几百行。

在程序的早期,我想做一些质量控制,如果没有足够的数据,我希望程序终止并返回 R 控制台。否则,我希望执行其余代码。

我已经尝试过break, browser,并且quit它们都没有停止程序其余部分的执行(并quit停止执行以及完全退出 R,这不是我想要发生的事情)。我最后的手段是创建如下if-else声明:

 if(n < 500){}
 else{*insert rest of program here*}

但这似乎是不好的编码习惯。我错过了什么吗?

4

9 回答 9

67

stopifnot()如果您希望程序产生错误,您可以使用该函数:

foo <- function(x) {
    stopifnot(x > 500)
    # rest of program
}
于 2013-07-24T14:56:30.077 回答
15

也许您只是想在某个时候停止执行长脚本。IE。就像您想在 C 或 Python 中硬编码 exit() 一样。

print("this is the last message")
stop()
print("you should not see this")
于 2015-04-19T23:07:14.470 回答
15

已编辑。感谢@Droplet,他找到了一种无需.Internal(): 这是一种exit()在 R 中实现命令的方法。

exit <- function() { invokeRestart("abort") }    

print("this is the last message")
exit()
print("you should not see this")

只是经过轻微测试,但是当我运行它时,我看到this is the last message然后脚本中止,没有任何错误消息。

以下是我原始答案中更丑陋的版本。

exit <- function() {
  .Internal(.invokeRestart(list(NULL, NULL), NULL))
}
于 2017-05-10T13:43:02.330 回答
14

反转你的 if-else 结构:

if(n >= 500) {
  # do stuff
}
# no need for else
于 2013-07-24T14:46:49.650 回答
10

编辑:似乎 OP 正在运行一个长脚本,在这种情况下,只需要在质量控制之后用

if (n >= 500) {

.... long running code here

}

如果打破一个函数,你可能只是想要return(),无论是明确的还是隐含的。

例如,显式的双重返回

foo <- function(x) {
  if(x < 10) {
    return(NA)
  } else {
    xx <- seq_len(x)
    xx <- cumsum(xx)
  }
  xx ## return(xx) is implied here
}

> foo(5)
[1] 0
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55

通过return()暗示,我的意思是最后一行就好像你已经完成了return(xx),但不调用return().

有些人考虑使用多重回报不好的风格;在长函数中,跟踪函数退出的位置可能变得困难或容易出错。因此,另一种方法是使用单个返回点,但使用if () else ()子句更改返回对象。这样的修改foo()将是

foo <- function(x) {
  ## out is NA or cumsum(xx) depending on x
  out <- if(x < 10) {
    NA
  } else {
    xx <- seq_len(x)
    cumsum(xx)
  }
  out ## return(out) is implied here
}

> foo(5)
[1] NA
> foo(10)
 [1]  1  3  6 10 15 21 28 36 45 55
于 2013-07-24T14:47:01.400 回答
4

这是一个老问题,但还没有一个干净的解决方案。这可能没有回答这个特定的问题,但是那些正在寻找“如何优雅地退出 R 脚本”的答案的人可能会在这里找到答案。似乎 R 开发人员忘记实现 exit() 函数。无论如何,我发现的窍门是:

continue <- TRUE

tryCatch({
     # You do something here that needs to exit gracefully without error.
     ...

     # We now say bye-bye         
     stop("exit")

}, error = function(e) {
    if (e$message != "exit") {
        # Your error message goes here. E.g.
        stop(e)
    }

    continue <<-FALSE
})

if (continue) {
     # Your code continues here
     ...
}

cat("done.\n")

基本上,您使用标志来指示指定代码块的继续与否。然后,您使用该stop()函数将自定义消息传递给函数的错误处理程序tryCatch()。如果错误处理程序收到您的消息以正常退出,那么它只是忽略错误并将继续标志设置为FALSE.

于 2018-04-18T08:28:57.310 回答
1

这里:

if(n < 500)
{
    # quit()
    # or 
    # stop("this is some message")
}
else
{
    *insert rest of program here*
}

两者都quit()stop(message)退出您的脚本。如果您从 R 命令提示符获取脚本,那么quit()也将从 R 退出。

于 2014-02-23T21:07:04.643 回答
1

我有一个类似的问题:退出当前函数,但不想完成其余代码。最后我通过只运行一次的 for() 循环解决了它。在 for 循环中,您可以设置几个不同的条件以离开当前循环(函数)。

  for (i in T) {
    print('hello')
    if (leave.condition) next
    print('good bye')
  }
于 2021-04-30T08:42:13.350 回答
0

您可以使用“工具”包中的pskill功能R来中断当前进程并返回控制台。具体来说,我在每个脚本开头的启动文件中定义了以下函数。但是,您也可以直接在代码开头复制它。然后halt()在代码中的任何位置插入以即时停止脚本执行。此功能在 GNU/Linux 上运行良好,从R文档来看,它也应该在 Windows 上运行(但我没有检查)。

# halt: interrupts the current R process; a short iddle time prevents R from
# outputting further results before the SIGINT (= Ctrl-C) signal is received 
halt <- function(hint = "Process stopped.\n") {
    writeLines(hint)
    require(tools, quietly = TRUE)
    processId <- Sys.getpid() 
    pskill(processId, SIGINT)
    iddleTime <- 1.00
    Sys.sleep(iddleTime)
}
于 2014-08-20T11:30:20.170 回答