为什么`lapply`会自动返回赋值结果?
q <- lapply(1:3, function(x) x ** 2)
## returns nothing, because it is an assignment
# however, how you explain this?:
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
# while this gives the same but is logical (q is stated as return value).
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) {q <- lapply(v, function(x) x ** 2);q})
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
为什么在第二个表达式中,虽然innerlapply
只是在函数结束时被赋值q
但q
没有被调用,但赋值的值却被返回给了outerlapply
并因此被收集?请问,有人对这种现象有解释吗?
它也适用于 =
lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q = lapply(c(v), function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
回答
答案就在返回值的的赋值操作。赋值运算符<-
不仅将值写入调用环境中的变量,而且实际上将赋值本身无形地返回给调用者。
请记住,R 中的所有操作实际上都是函数。当你做
x <- 3
你实际上在做
`<-`(x, 3)
`<-`(x, 3)
这不仅在调用环境中创建符号“x”并将值 3 分配给该符号,而且无形地将值 3 返回给调用者。
y <- 2
y
#> [1] 2
y <- `<-`(x, 3)
y
#> [1] 3
要看到这一点,请考
y <- (x <- 4)
y
#> [1] 4
y <- (x <- 4)
y
#> [1] 4
虑:
y <- 2 y #&
y <- x <- 5 y #> [1] 5
gt; [1] 2
y <- `<-`(x, 3)
y
#> [y <- x <- 5 y #> [1] 5
1] 3
或者等效地,
事实上,由于 R 的求值顺序,我们甚至可以这样做:
这是在同一行上将多个变量设置为相同值的一种巧妙方法。
现在考虑你在你的内部使用的 lambda 函数
lapply
:看看当我们将此函数视为独立函数时会发生什么:
正如预测的那样,什么也没有发生。但是当我们这样做时会发生什么:
如果 func(1:3) 没有返回任何东西,那么
a
现在大概应该是空的。但它不是...
因为赋值的值是无形地返回给调用者的,所以我们能够将它赋值给调用范围内的一个值。因此,做
function(v) q <- lapply(v, function(x) x ** 2)
将应用于所有列表元素的内部函数的值分配给新列表。这个列表不是隐形返回,而是正常返回。
所以这是预期的行为。
- This is a great answer! Everyone should upvote this. I started to write this and decided it was going to take too long to explain. Well done @AllanCameron!