【问题标题】:Make list of functions with lapply使用 lapply 制作函数列表
【发布时间】:2017-05-05 18:18:48
【问题描述】:

有没有办法使用 lapply 制作以下函数列表?下面,我列出了一个名为“long”的列表。我想使用 lapply (或 for 循环)简化代码,但似乎都不起作用。谢谢。

#This works as expected
long <- list(function(x) x <- within(x, DATE <- as.Date("2013-01-01")),
             function(x) x <- within(x, DATE <- as.Date("2014-01-01")),
             function(x) x <- within(x, DATE <- as.Date("2015-01-01")))

#This does not work
long <- lapply(2013:2015, function(i) x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-"))))

#This does not work
for (i in 2013:2015) long <- list(function(x) x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-"))))

【问题讨论】:

    标签: r list function auto-generate


    【解决方案1】:

    也许最简单的方法是添加另一个function。

    long <- lapply(2013:2015,
                  function(i) function(x) {
                               x <- within(x, DATE <- as.Date(paste(i, "01", "01", sep = "-")))})
    

    检查元素是否为函数

    typeof(long[[1]])
    [1] "closure"
    

    测试一下

    # empty list, x
    x <- list()
    x <- long[[1]](x)
    x
    $DATE
    [1] "2013-01-01"
    

    正如@Roland 在 cmets 中提到的,强制评估 i 参数会更安全。

    long <- lapply(2013:2015, function(i) {
                                force(i);
                                function(x) x <- within(x,
                                                DATE <- as.Date(paste(i, "01", "01", sep = "-")))
                               })
    

    【讨论】:

    • 谢谢,但这不会产生与我的示例相同的结果。
    • @user1491868 唯一的区别是i 的值存储在函数的封闭环境中。可以使用它们并提供与您的示例相同的返回值。
    • @lmo 我想我已经过时了,但我会force(i)。
    • 您可以说这个答案与我的不同之处在于,这是获取日期的“运行时”解决方案,而我的是“编译时”。
    • @HongOoi 一个很好的类比,但它暗示使用这些函数时的性能差异比我预期的要大。
    【解决方案2】:

    有一些bquote魔法:

    dates <- c("2013-01-01", "2014-01-01", "2015-01-01")
    
    lapply(dates, function(d) eval(bquote(function(x) within(x, DATE <- as.Date(.(d))))))
    
    #[[1]]
    #function (x) 
    #within(x, DATE <- as.Date("2013-01-01"))
    #<environment: 0x000002b1815ba450>
    #
    #[[2]]
    #function (x) 
    #within(x, DATE <- as.Date("2014-01-01"))
    #<environment: 0x000002b1815ae320>
    #
    #[[3]]
    #function (x) 
    #within(x, DATE <- as.Date("2015-01-01"))
    #<environment: 0x000002b1815a1520>
    

    (赋值x &lt;- within(...)在函数内部是多余的。)

    解释:bquote 创建了一个 unevalated 表达式对象,用 .(*) 标记的符号替换为它们的值。 eval 然后计算表达式。

    在这种情况下,bquote 创建一个调用以使用 function(x) ... 生成函数并插入特定日期,因此如果 d 具有值 "2013-01-01",则 bquote(function(x) ... as.Date(.(d)) 会导致 未评估 表达式function(x) ... as.Date("2013-01-01")。当你在 this 上调用 eval 时,结果是一个包含你想要的函数体的函数对象。

    有关详细信息,请参阅 ?eval 和 ?bquote。

    【讨论】:

    • 此列表与我的示例相同,但适用于 部分。
    • 没关系,这就是lapply创建的环境。它仍然可以工作。
    • 谢谢,这很好。如果您有时间解释“eval”和“bquote”在做什么,那就太好了。
    • 见?eval 和?bquote。后者创建一个未计算的表达式对象,用.(*) 标记的符号替换为它们的值。前者然后评估表达式。在这种情况下,bquote 创建一个调用以使用 function(x) ... 生成函数并插入特定日期。
    • 继续:如果d 的值是"2013-01-01",那么bquote(function(x) ... as.Date(.(d)) 会产生未计算的表达式function(x) ... as.Date("2013-01-01")。当你在 this 上调用 eval 时,结果是一个包含你想要的函数体的函数对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-08
    • 1970-01-01
    • 2023-04-04
    • 2015-10-12
    • 2018-06-19
    相关资源
    最近更新 更多