【问题标题】:Why `lapply` returns result of assignment automatically?为什么`lapply`会自动返回赋值结果?
【发布时间】:2020-12-03 16:17:25
【问题描述】:
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

为什么在第二个表达式中,虽然内部lapply只是赋值给q但是q没有在函数结束时调用,赋值的值 被返回到外部lapply 并因此被收集? 请问,有人对这种现象有解释吗?

它也适用于=

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 return-value variable-assignment lapply


    【解决方案1】:

    答案在于赋值操作返回值。赋值运算符&lt;-不仅在调用环境中向变量写入值,它实际上是在不可见的情况下将分配的值本身返回给调用者。

    请记住,R 中的所有操作实际上都是函数。当你这样做时

    x <- 3
    

    你确实在做

    `<-`(x, 3)
    

    这不仅在调用环境中创建符号“x”并将值 3 分配给该符号,而且不可见地将值 3 返回给调用者。要看到这一点,请考虑:

    y <- 2
    y
    #> [1] 2
    
    y <- `<-`(x, 3)
    y
    #> [1] 3
    

    或者等价的,

    y <- (x <- 4)
    y
    #> [1] 4
    

    事实上,由于 R 的求值顺序,我们甚至可以这样做:

    y <- x <- 5
    y
    #> [1] 5
    

    这是在同一行将多个变量设置为相同值的一种巧妙方法。

    现在考虑您在 lapply 中使用的 lambda 函数:

    function(v) q <- lapply(v, function(x) x ** 2)
    

    看看当我们将此函数视为独立函数时会发生什么:

    func <- function(v) q <- lapply(v, function(x) x ** 2)
    
    func(1:3)
    

    正如预测的那样,什么都没有发生。但是当我们这样做时会发生什么:

    a <- func(1:3)
    

    如果 func(1:3) 没有返回任何东西,那么大概a 现在应该是空的。

    但不是……

     a
    #> [[1]]
    #> [1] 1
    #>
    #> [[2]]
    #> [1] 4
    #>
    #> [[3]]
    #> [1] 9
    

    因为赋值的值是不可见地返回给调用者的,所以我们能够将它赋值给调用范围内的一个值。因此,做

    lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
    

    将应用于所有列表元素的内部函数的值分配给一个新列表。此列表不是不可见地返回,而是正常返回。

    所以这是预期的行为。

    【讨论】:

    • 非常感谢。我不知道&lt;- 默默地返回值! print(q &lt;- 3) 确实打印了 3
    • @Gwang-JinKim 完全正确!
    • 这是一个很好的答案!每个人都应该对此表示赞同。我开始写这篇文章,并决定要花很长时间来解释。干得好@AllanCameron!
    猜你喜欢
    • 2018-12-06
    • 1970-01-01
    • 2011-06-19
    • 2017-12-07
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 2017-02-21
    相关资源
    最近更新 更多