exists and sapply:为什么这些功能不同?
exists and sapply: why are these functions different?
为什么下面的两个函数fn
和gn
不同?我不认为他们应该是,但我一定遗漏了一些东西。
vars <- letters[1:10]
a <- b <- 1
fn <- function (d) {
sapply( vars, exists )
}
gn <- function (d) {
sapply( vars, function (x) { exists(x) } )
}
fn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
gn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
exists("i")
# [1] FALSE
有两个区别:
gn(d=2)
说 d
存在,但为什么 fn(d=2)
不存在?
fn(d=2)
表示 i
存在,而 gn(d=2)
不存在。这很令人费解,因为我没有在任何地方定义 i
。
注意:这是在 R 版本 3.2.0 上,似乎第二个行为是该版本的新行为(见下文)。
关于i
,我无法重现。但我会尝试解释其他差异,首先是两个函数都找到的 c
和只有 gn()
找到的 d
。
两个函数都找到了 c
,因为它们正在寻找基函数 c
。
现在关于 d
,R 是词法范围的。你可能想看看这个问题 Environments in R, mapply and get。因此,在第一个函数 fn()
中,exists
不是在 fn()
的局部环境中寻找 d
,而是在全局环境中(并且没有d
那里)。
但是请注意,在 gn()
中,您将使用 exists()
的函数定义为 gn()
中的匿名函数。看:
gn <- function (d) {
sapply( vars, function (x) { exists(x) } ) # defined anon function
}
所以gn()
的环境就是匿名函数function (x) { exists(x) }
的父环境。这就是为什么它在 gn
内搜索并找到局部参数 d
,返回 TRUE
.
重要的区别是 "d" 的值,即调用中正式变量的名称。 . exists
函数的默认设置是 "above" 而不是 "in"。在第一个实例中,.GlobalEnv 中没有 "d" 命名的实体,这是调用函数的地方。在第二种情况下,周围环境中有一个d
(作为名称)。
正在寻找 "i" 或 "c" 的人正在寻找函数 c
或 for 循环的索引。 (索引变量在 for 循环结束时持续存在。)
看来 "i" 值差异仅出现在最新版本中,我在这台机器上没有看到,因为它在我当前的 OS 版本中已达到 3.1.3 的最大值。在当前会话中使用 "i" 作为 for 循环中的索引变量的人(或正在使用较早保存的环境)也可能发生这种情况。
这是奇怪的行为。我相信对此有一个合理的解释。这是一个全新的 R 会话。这次我什至没有使用 RStudio,它产生相同的输出。
R version 3.2.0 (2015-04-16) -- "Full of Ingredients"
Copyright (C) 2015 The R Foundation for Statistical Computing
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
> exists('i')
[1] FALSE
> sapply('i', exists)
i
TRUE
更奇怪的行为:
> lapply('i', exists)
[[1]]
[1] TRUE
> vapply('i', exists, logical(1))
i
TRUE
> tapply('i', 'i', exists)
i
TRUE
> mapply(exists, list('i'))
[1] FALSE
> rapply(list('i'), exists)
[1] FALSE
> exists('i')
[1] FALSE
> ls()
character(0)
mapply
和 rapply
return FALSE
。它们都需要列表作为参数。这可能与它有关。也许其他应用函数在 R 中的某些环境中选择了一些东西,而裸函数和一些应用函数则没有。
为什么 i
不一样...
看起来 R 3.2 中有变化。索引变量 i
是 lapply
的 added to the current environment(这是 sapply
实际调用的)。这与新行为一起强制评估传递给您正在应用的函数的参数。这意味着您现在可以访问循环中当前迭代的索引。
fn
和 gn
行为不同的原因是 exists()
在调用它的环境中查找。在 fn
的情况下,这是创建此 i
变量的环境。在 gn
的情况下,它正在查找匿名函数的环境。当 R 在本地环境中找不到符号时,它会根据定义函数的位置而不是调用它们的位置来搜索环境。这意味着 R 将找不到 i
变量,因为您的匿名函数是在 i
变量不存在的地方定义的。
我们可以写个小辅助函数,方便抓取当前索引
idx <- function() get("i", parent.frame(2))
sapply(letters[1:3], function(x) paste(idx(), x))
# a b c
# "1 a" "2 b" "3 c"
据我所知,这是目前未记录的行为。它可能会在 R 的未来版本中发生变化。
为什么 d
不一样...
与 d
变量的差异是一个更直接的范围问题。 R 再次创建一个新环境,用于调用函数 exists
。此环境的父级是基础环境。因此,当您调用 exists
时,它会查找从何处调用它(这是存在 i
的环境)并且由于它在那里找不到 d
,因此它会搜索下一个父级基地环境。从不搜索当前函数环境。您可以使用
明确搜索当前环境
fn <- function (d) {
sapply( vars, exists, where=environment() )
}
fn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
有关 R 环境的更多信息,我建议您阅读 Environments section of Advanced R
为什么下面的两个函数fn
和gn
不同?我不认为他们应该是,但我一定遗漏了一些东西。
vars <- letters[1:10]
a <- b <- 1
fn <- function (d) {
sapply( vars, exists )
}
gn <- function (d) {
sapply( vars, function (x) { exists(x) } )
}
fn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
gn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
exists("i")
# [1] FALSE
有两个区别:
gn(d=2)
说d
存在,但为什么fn(d=2)
不存在?fn(d=2)
表示i
存在,而gn(d=2)
不存在。这很令人费解,因为我没有在任何地方定义i
。
注意:这是在 R 版本 3.2.0 上,似乎第二个行为是该版本的新行为(见下文)。
关于i
,我无法重现。但我会尝试解释其他差异,首先是两个函数都找到的 c
和只有 gn()
找到的 d
。
两个函数都找到了 c
,因为它们正在寻找基函数 c
。
现在关于 d
,R 是词法范围的。你可能想看看这个问题 Environments in R, mapply and get。因此,在第一个函数 fn()
中,exists
不是在 fn()
的局部环境中寻找 d
,而是在全局环境中(并且没有d
那里)。
但是请注意,在 gn()
中,您将使用 exists()
的函数定义为 gn()
中的匿名函数。看:
gn <- function (d) {
sapply( vars, function (x) { exists(x) } ) # defined anon function
}
所以gn()
的环境就是匿名函数function (x) { exists(x) }
的父环境。这就是为什么它在 gn
内搜索并找到局部参数 d
,返回 TRUE
.
重要的区别是 "d" 的值,即调用中正式变量的名称。 . exists
函数的默认设置是 "above" 而不是 "in"。在第一个实例中,.GlobalEnv 中没有 "d" 命名的实体,这是调用函数的地方。在第二种情况下,周围环境中有一个d
(作为名称)。
正在寻找 "i" 或 "c" 的人正在寻找函数 c
或 for 循环的索引。 (索引变量在 for 循环结束时持续存在。)
看来 "i" 值差异仅出现在最新版本中,我在这台机器上没有看到,因为它在我当前的 OS 版本中已达到 3.1.3 的最大值。在当前会话中使用 "i" 作为 for 循环中的索引变量的人(或正在使用较早保存的环境)也可能发生这种情况。
这是奇怪的行为。我相信对此有一个合理的解释。这是一个全新的 R 会话。这次我什至没有使用 RStudio,它产生相同的输出。
R version 3.2.0 (2015-04-16) -- "Full of Ingredients"
Copyright (C) 2015 The R Foundation for Statistical Computing
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
> exists('i')
[1] FALSE
> sapply('i', exists)
i
TRUE
更奇怪的行为:
> lapply('i', exists)
[[1]]
[1] TRUE
> vapply('i', exists, logical(1))
i
TRUE
> tapply('i', 'i', exists)
i
TRUE
> mapply(exists, list('i'))
[1] FALSE
> rapply(list('i'), exists)
[1] FALSE
> exists('i')
[1] FALSE
> ls()
character(0)
mapply
和 rapply
return FALSE
。它们都需要列表作为参数。这可能与它有关。也许其他应用函数在 R 中的某些环境中选择了一些东西,而裸函数和一些应用函数则没有。
为什么 i
不一样...
看起来 R 3.2 中有变化。索引变量 i
是 lapply
的 added to the current environment(这是 sapply
实际调用的)。这与新行为一起强制评估传递给您正在应用的函数的参数。这意味着您现在可以访问循环中当前迭代的索引。
fn
和 gn
行为不同的原因是 exists()
在调用它的环境中查找。在 fn
的情况下,这是创建此 i
变量的环境。在 gn
的情况下,它正在查找匿名函数的环境。当 R 在本地环境中找不到符号时,它会根据定义函数的位置而不是调用它们的位置来搜索环境。这意味着 R 将找不到 i
变量,因为您的匿名函数是在 i
变量不存在的地方定义的。
我们可以写个小辅助函数,方便抓取当前索引
idx <- function() get("i", parent.frame(2))
sapply(letters[1:3], function(x) paste(idx(), x))
# a b c
# "1 a" "2 b" "3 c"
据我所知,这是目前未记录的行为。它可能会在 R 的未来版本中发生变化。
为什么 d
不一样...
与 d
变量的差异是一个更直接的范围问题。 R 再次创建一个新环境,用于调用函数 exists
。此环境的父级是基础环境。因此,当您调用 exists
时,它会查找从何处调用它(这是存在 i
的环境)并且由于它在那里找不到 d
,因此它会搜索下一个父级基地环境。从不搜索当前函数环境。您可以使用
fn <- function (d) {
sapply( vars, exists, where=environment() )
}
fn(d=2)
# a b c d e f g h i j
# TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
有关 R 环境的更多信息,我建议您阅读 Environments section of Advanced R