作为sapply函数参数的美元符号运算符未按预期工作

14

我有以下清单

test_list=list(list(a=1,b=2),list(a=3,b=4))

我想提取所有列表元素名称为a的元素。

我可以通过以下方式实现

sapply(test_list,`[[`,"a")

这使我得到了正确的结果。

#[1] 1 3
尝试使用美元符号操作符“$”时,我得到了“NULL”的结果。
sapply(test_list,`$`,"a")
#[[1]]
#NULL
#
#[[2]]
#NULL

然而,如果我将其用于test_list的单个元素上,则它按预期工作。

`$`(test_list[[1]],"a")
#[1] 1

我是否漏看了一些显而易见的东西?

2个回答

11

评估 vs. 不评估

[[ 会评估其参数,而 $ 则不会。 L[[a]] 获取变量 a 中保存的名称对应的 L 组件。 $ 只将参数名本身作为字符串传递,所以 L$a 找到 L"a" 组件。此时,a 不被视为保存组件名称的变量,只是一个字符串。

下面,因为变量 b 的值为 "a",所以 L[[b]] 返回名为 "a"L 组件,而 L$b 返回名为 "b"L 组件,因为该语法中的 b 不被视为变量,而是被视为传递的字符串本身。

L <- list(a = 1, b = 2)
b <- "a"
L[[b]] # same as L[["a"]] since b holds a
## [1] 1
L$b  # same as L[["b"]] since b is regarded as a character string to be passed
## [1] 2

sapply

现在我们理解了$和[[之间的主要区别,为了看清sapply的运行情况,请考虑以下示例。我们将test_list的每个元素变成"foo"对象,并定义了自己的$.foo[[.foo方法,这些方法仅通过name参数显示R传递给方法的内容:

foo_list <- test_list
class(foo_list[[1]]) <- class(foo_list[[2]]) <- "foo"

"$.foo" <- "[[.foo" <- function(x, name) print(name)

result <- sapply(foo_list, "$", "a")
## "..."
## "..."

result2 <- sapply(foo_list, "[[", "a")    
## [1] "a"
## [1] "a"

在第一种情况下发生的是sapply调用了whatever$...,但...没有被评估,所以它将查找一个列表组件,该组件实际上命名为"...",当然,没有这样的组件,因此whatever$...是NULL,因此在问题输出中显示了NULL。在第二种情况下,whatever[[[...]]]评估为whatever[["a"]],因此观察到了结果。


6
根据我的了解,这是两种因素的结合。
首先,匹配但不评估$的第二个元素,因此它不能是变量
其次,当参数传递给函数时,它们被分配给函数调用中相应的变量。 当传递给sapply时,"a"被分配给一个变量,因此将无法再使用$。 我们可以通过运行来看到这一点。
sapply("a", print)
[1] "a"
  a 
"a"

这可能导致出现奇怪的结果,就像这样。
sapply(test_list, function(x, a) {`$`(x, a)})
[1] 1 3

尽管a是一个变量(甚至还没有被赋值),$将其与列表中元素的名称进行匹配。


非常有趣的答案!它基本上表明,已经 x="a";"$"(test_list[[1]],x); 给出了一个不正确的结果。 - cryo111
同样地,就像你所说的那样,"$"(test_list[[1]],a)会给出1,尽管没有定义对象a - cryo111

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