R:尽管条件为 FALSE,IF 语句仍评估表达式?

R: IF statement evaluating expression despite condition being FALSE?

我在 R 中有一个很大的函数,用户可以不 include/specify 一个对象。如果是,代码会检查以确保该对象中的名称与另一个对象中的名称相匹配。如果他们不这样做,则无需进行该检查。代码行是:

if(exists("grids")) if(!all(expvarnames %in% names(grids))) {stop("Not all expvar column names found as column names in grids")}

但我收到以下错误:

Error in match(x, table, nomatch = 0L) : argument "grids" is missing, with no default

好吧,在这个试验中 运行,网格应该是缺失的。如果我尝试

if(exists("grids")) print("yay")

然后什么都不打印,即没有网格意味着表达式没有被计算,这是我所期望的。那么谁能想到为什么 R 似乎正在评估主要示例中的后续 IF 语句?我应该在第二个大括号周围加上另一组大括号吗??

谢谢!

编辑:更多问题。从变量的函数列表中删除 "grids," 意味着如果没有名为 grids 的对象并且您没有在调用中指定它(即 function(x,grids=whatever)),它就可以工作。在函数变量列表中保留 "grids," 意味着如果有一个名为 grids 的对象并且您在调用中指定它,它就可以工作。

请看这个:http://i.imgur.com/9mr1Lwi.png

使用 exists(grids) 已经过时了,因为 exists 需要 "quotes" 并且没有 em 一切都会失败。有了它们 ("grids"),我需要决定是否将 "grids," 保留在函数列表中。如果我不这样做,但我在调用 (function(x,grids=whatever)) 中指定了它,那么我会得到未使用的参数失败。如果我这样做了,但没有在调用中指定它,因为网格不存在并且我不想使用它,我会得到匹配错误,网格没有默认值。

我该如何解决这个问题?也许在函数变量列表中将其列为 grids="NULL",然后而不是 if(exists("grids"))if(grids!="NULL")

我仍然不知道为什么会出现原来的匹配问题。匹配来自 expvarnames/grids 名称检查器,它位于 if(exists("grids")) 之后,计算结果为 FALSE。 WAaaaaaaiiiittttt..... 如果我在函数变量列表中指定网格,即简单地放置 function(x,grids,etc){do stuff},这是否意味着函数在其环境中创建了一个名为网格的对象? 伙计,这真是太糟糕了....

testfun <- function(x,grids)
{if(exists("grids")) globalgrids<<-grids
print(x+1)}
testfun(1) # Error in testfun(1) : argument "grids" is missing, with no default

testfun <- function(x,grids)
{if(exists("grids")) a<<-c(1,2,3)
  print(x+1)}
testfun(1) #2 (and globally assigns a)

所以在第一个例子中,函数似乎创建了一个名为 "grids" 的对象,因为 exists("grids") 的计算结果为真。但是然后,在同一条线上,当被要求对网格做些什么时,它说它不存在!薛定谔的对象?! 这在示例 2 中得到了证明:grids 评估为 true 并且 a 被全局分配,然后该函数执行其操作。疯狂。完全疯狂。有谁知道为什么会发生这种荒谬的事情?在函数变量列表中使用我的 grids="NULL" default 是最好的解决方案吗? 谢谢。

可重现的例子,如果你愿意,但我已经为每个排列完成了:

testfun <- function(x,grids)
{if(exists("grids")) if(!all(expvarnames %in% names(grids))) {stop("Not all expvar column names found as column names in grids")}
  print(x+1)}
testfun(1)
testfun(x=1,grids=grids)
grids<-data.frame(c(1,2,3),c(1,2,3),c(1,2,3))
expvarnames <- c("a","b","c")
colnames(grids) <- c("a","b","c")

解决方案

调整您的示例使用:

testfun <- function(x,grids = NULL)
{
   if(!is.null(grids)){
     if(!all(expvarnames %in% names(grids))){
       stop("Not all expvar column names found as column names in grids")
     }
     print(x+1)
   }
}

使用这个 testfun(1) 将 return 什么都没有。通过在函数中将默认参数指定为 NULL 函数然后检查这个(即没有指定参数)然后如果是这样就不会继续函数。

出现问题的原因

我们通过每个示例:

testfun <- function(x,grids)
{if(exists("grids")) globalgrids<<-grids
print(x+1)}

testfun(1) # Error in testfun(1) : argument "grids" is missing, with no default

这里我们调用函数testfun,只给出x参数。 testfun 知道它需要两个参数,因此创建局部变量 xgrids。然后我们给 x 一个参数,所以它将值赋给 xgrids 没有参数,但是变量仍然被创建,即使没有赋值给它。所以 grids 存在,但没有价值。

由此 exists("grids") 将是 TRUE,但是当我们尝试执行 globalgrids<<-grids 时,我们会得到一个错误,因为 grids 没有被赋值,并且所以我们不能给 globalgrids 赋值。

testfun <- function(x,grids)
{if(exists("grids")) a<<-c(1,2,3)
  print(x+1)}
testfun(1) #2 (and globally assigns a)

不过这很好。 grids 与前一种情况一样存在,我们实际上从未尝试访问存储在 grids 中的值,这会导致错误,因为我们还没有分配一个值。

在解决方案中,我们只是为 grids 设置了默认值,这意味着无论何时尝试访问变量,我们总能得到一些东西。与前面的情况不同,我们将得到 NULL,而不是那里没有存储任何内容。

要点在于,当您在函数中声明参数时,每次使用该函数时都会创建它们。它们存在。但是,如果您不在函数调用中为它们分配值,那么它们将存在,但没有任何价值。然后,当您尝试使用它们时,它们缺少值会引发错误。

> a <- c(1,2,3,4)
> b <- c(2,4,6,8)
> if(exists("a")) if(!all(a %in% b)) {stop("Not all a in b")}

Error: Not all a in b

> rm(a)
> if(exists("a")) if(!all(a %in% b)) {stop("Not all a in b")}
>

a 不存在时,表达式不会按预期进行计算。在测试您的第一个表达式之前,请确保控制台中的 运行 rm(grids) 不存在 grids

Richard Scriven 的评论让我开始思考:grids 是我函数中的一个参数,但它是可选的,因此可能不应该指定(就像“...”可选函数中的任何内容)。我把它注释掉了,它起作用了。万岁,大家加油。