使用字符串作为函数的参数
Using strings as arguments of a function
SO 上有很多关于此主题的问题,包括 this question on how to evaluate expressions, this one showing some disagreement about using eval
, and this answer 显示 eval(substitute(.))
技巧。
了解非标准评估 (NSE) 的一个很好的参考是 Hadley Wickham 的 metaprogramming section of Advanced R。
我注意到答案中存在很多分歧,其中一些表示 using strings as something to be evaluated.
存在问题
我正在使用字符串作为子函数的参数。
这是一个代表:
# Consider a little toy function:
little_fun <- function(z = 2, y = 1) {
(z + 2) / y
}
little_fun()
#> [1] 4
# I can call little_fun() on lists of arguments:
z_list <- c(1,2,3)
purrr::map_dbl(.x = z_list, ~ little_fun(z = (.x))) # This is basically a tidyverse equivalent for lapply()
#> [1] 3 4 5
# or also:
z_list <- c(1,2,3)
y_list <- c(-1, 0, 1)
purrr::map2_dbl(.x = z_list, .y = y_list, ~ little_fun(z = (.x), y = (.y))) # again, similar to mapply()
#> [1] -3 Inf 5
# But I also want to assign the parameters from a more general parent function:
big_fun <- function(par = "y") {
stopifnot(par %in% c("z", "y"))
par_list <- c(1,2,3)
purrr::map_dbl(.x = par_list, ~ little_fun(par = (.x))) # <--- key line <---
}
big_fun()
#> Error in little_fun(par = (.x)): unused argument (par = (.x))
我的问题:我仍然无法获取代码运行。
我的问题:为什么使用字符作为函数参数不好?我应该避免这种情况吗?如何?我想了解如何改进我的推理并学习可用的替代方案。
我不反对 chinsoon12 对你 "Should I avoid this?"
问题的回答
"protect yourself against future stupidity" – chinsoon12
话虽如此,动态分配的参数名称是 do.call
派上用场的地方。
big_fun <- function(par = "y") {
stopifnot(par %in% c("z", "y"))
par_list <- c(1,2,3)
purrr::map_dbl(.x = par_list, ~do.call(little_fun, as.list(setNames(.x, par))))
}
big_fun()
# [1] 4.000000 2.000000 1.333333
big_fun("z")
# [1] 3 4 5
我个人发现像这样的编程有时会令人费解且有问题,而在其他时候可能是优雅地解决某些问题的唯一方法。有时它是可用的最简洁、健壮和高效的解决方案。
只是为了检查一下,我相信 big_fun()
本身应该匹配:
sapply(1:3, little_fun, z=2)
# [1] 4.000000 2.000000 1.333333
SO 上有很多关于此主题的问题,包括 this question on how to evaluate expressions, this one showing some disagreement about using eval
, and this answer 显示 eval(substitute(.))
技巧。
了解非标准评估 (NSE) 的一个很好的参考是 Hadley Wickham 的 metaprogramming section of Advanced R。
我注意到答案中存在很多分歧,其中一些表示 using strings as something to be evaluated.
我正在使用字符串作为子函数的参数。
这是一个代表:
# Consider a little toy function:
little_fun <- function(z = 2, y = 1) {
(z + 2) / y
}
little_fun()
#> [1] 4
# I can call little_fun() on lists of arguments:
z_list <- c(1,2,3)
purrr::map_dbl(.x = z_list, ~ little_fun(z = (.x))) # This is basically a tidyverse equivalent for lapply()
#> [1] 3 4 5
# or also:
z_list <- c(1,2,3)
y_list <- c(-1, 0, 1)
purrr::map2_dbl(.x = z_list, .y = y_list, ~ little_fun(z = (.x), y = (.y))) # again, similar to mapply()
#> [1] -3 Inf 5
# But I also want to assign the parameters from a more general parent function:
big_fun <- function(par = "y") {
stopifnot(par %in% c("z", "y"))
par_list <- c(1,2,3)
purrr::map_dbl(.x = par_list, ~ little_fun(par = (.x))) # <--- key line <---
}
big_fun()
#> Error in little_fun(par = (.x)): unused argument (par = (.x))
我的问题:我仍然无法获取代码运行。
我的问题:为什么使用字符作为函数参数不好?我应该避免这种情况吗?如何?我想了解如何改进我的推理并学习可用的替代方案。
我不反对 chinsoon12 对你 "Should I avoid this?"
问题的回答"protect yourself against future stupidity" – chinsoon12
话虽如此,动态分配的参数名称是 do.call
派上用场的地方。
big_fun <- function(par = "y") {
stopifnot(par %in% c("z", "y"))
par_list <- c(1,2,3)
purrr::map_dbl(.x = par_list, ~do.call(little_fun, as.list(setNames(.x, par))))
}
big_fun()
# [1] 4.000000 2.000000 1.333333
big_fun("z")
# [1] 3 4 5
我个人发现像这样的编程有时会令人费解且有问题,而在其他时候可能是优雅地解决某些问题的唯一方法。有时它是可用的最简洁、健壮和高效的解决方案。
只是为了检查一下,我相信 big_fun()
本身应该匹配:
sapply(1:3, little_fun, z=2)
# [1] 4.000000 2.000000 1.333333