为何`$`作为sapply/lapply的FUN参数无法取列表元素而`[[`可行?
为什么
$和[[在sapply/lapply中作为FUN参数表现不同? 先看你的测试数据:
test_list <- list(list("name"="A","property"=1), list("name"="B","property"=2), list("name"="C","property"=3))
你发现用sapply(test_list, $, "property")返回一堆NULL,但换成[[就完全正常:
> sapply(test_list, `$`, "property") [[1]] NULL [[2]] NULL [[3]] NULL > sapply(test_list, `[[`, "property") [1] 1 2 3
甚至写匿名函数调用$也不行:
> sapply(test_list, function(x, y) `$`(x, y), y = "property") [[1]] NULL [[2]] NULL [[3]] NULL
但单独对单个列表元素调用$和[[都能正常拿到结果:
> `$`(test_list[[1]], 'property') [1] 1 > `[[`(test_list[[1]], 'property') [1] 1
这到底是怎么回事?其实核心原因在于**$的非标准求值特性**!
关键差异:非标准求值vs标准求值
[[是标准求值的运算符:它会先计算传入的第二个参数的实际值,再用这个值去索引列表。比如你传字符串"property",它就直接用这个字符串作为键去匹配子列表里的元素,不管是单独调用还是在sapply里传递参数,逻辑都一致,所以能正常工作。$是非标准求值的运算符:它默认把第二个参数当作一个**符号(symbol,也就是变量名)**来处理,而不是直接使用参数的字面值。
为什么sapply里用$会失效?
当你写sapply(test_list, $, "property")时,$的第二个参数是字符串"property",但$并不会直接用这个字符串去索引——它会尝试在当前环境中找一个名为"property"的变量,但你并没有定义这个变量,自然找不到对应的元素,只能返回NULL。
而单独调用$(test_list[[1]], 'property')时,R会做一个特殊处理:当你直接把字符串字面量传给$的第二个参数时,它会自动把这个字符串转换成对应的符号,所以能正确匹配到子列表里的"property"元素。但这种特殊处理只在直接传递字面量时生效,当你通过参数传递字符串(比如sapply的额外参数、匿名函数的参数)时,这个转换就不会发生了。
非要用$在sapply里生效?可以这样做
如果你一定要在sapply里使用$,可以把字符串转换成符号,比如用as.name():
sapply(test_list, function(x, y) `$`(x, as.name(y)), y = "property") # 结果:[1] 1 2 3
不过显然,直接用[[会更简单直接,不需要额外的转换步骤。
内容的提问来源于stack exchange,提问作者mt1022
相关产品推荐
相关产品推荐

