在地图中使用部分

时间:2017-03-10 10:49:17

标签: r purrr

我遇到了一个有趣的问题。我有三个变量的函数,让我们说(为了简单和透明)它是这样的:

my_fun <- function(a, b, c) paste(a, b, c, sep = '-')

我想为c anb a的多个组合创建仅包含参数b的多个函数。我正在使用函数map2partial(都来自包purrr)。

require(purrr)
funs <- map2(letters[1:5], LETTERS[1:5], partial, ...f = my_fun)

我希望函数列表中的每个函数产生不同的输出,但事实并非如此。

funs[[1]]('hi')    # [1] "e-E-hi"
funs[[3]]('hi')    # [1] "e-E-hi"
funs[[5]]('hi')    # [1] "e-E-hi"

我能够为我的问题创建不同的解决方案,所以我的问题不是&#34;如何做到&#34;。我很感兴趣为什么会这样做。

另一个使用基础mapply的示例:

mapply(partial, letters[1:5], LETTERS[1:5], MoreArgs = list(...f = my_fun))[[1]]('hi')
# [1] "e-E-hi"

1 个答案:

答案 0 :(得分:2)

问题源于partial使用延迟评估这一事实,map2表示存储.x.y而不是aA。幸运的是,有一个函数参数,我们可以使用:

funs <- map2(letters[1:5], LETTERS[1:5], partial, ...f = my_fun, .lazy = FALSE)

funs[[1]]('hi')
# [1] "a-A-hi"

如果您查看您的版本,我们会看到:

funs[[1]]

# function (...) 
# my_fun(.x[[i]], .y[[i]], ...)
# <environment: 0x00000000201d9598>

其他每一个都是一样的。

现在,如果我们调查那个环境,我们可以看到:

ls(envir = environment(funs[[1]]))
# [1] "i"

因此有一个对象存储在i,这将决定我们得到哪个.x.y,其值是:

get('i', environment(funs[[1]]))
# [1] 5

另请注意,您的参数也存储在那里,但由于它们以.开头而被隐藏:

ls(envir =     environment(funs[[1]]), all.names = TRUE)
# [1] "..." ".f"  ".x"  ".y"  "i" 
get('.x', envir = environment(funs[[1]]))
# [1] "a" "b" "c" "d" "e"

因此,对于所有这些,我们得到相同的结果。具体来说,执行的调用最终是:

my_fun(letters[1:5][[5]], LETTERS[1:5][[5]], 'hi')

惰性评估在这里并不好用,并且在map2内使用存储的内部循环计数器。