如何使用 tidyselect 助手初始化变量?
How to initialize a variable with a tidyselect helper?
我在某些函数中使用了 tidyselection,我必须将第一个参数与省略号连接起来,因为它可能是需要特定处理的特定 class。
正常行为是这样的:
foo = function(x, ...){
xloc = eval_select(expr(c(x, ...)), data = iris)
return(xloc)
}
foo(everything())
当 x
为 NULL
时,我想将 everything()
作为默认值(我不能将它直接放在 header 中原因).
很遗憾,不允许使用此语法:
bar = function(x, ...){
if(is_null(x))
x=everything() #throws an error
xloc = eval_select(expr(c(x, ...)), data = iris)
return(xloc)
}
bar(NULL)
# Error: `everything()` must be used within a *selecting* function.
# i See <https://tidyselect.r-lib.org/reference/faq-selection-context.html>.
我尝试用我知道的所有 "mystic" 函数包装 everything()
:parse
、deparse
、call
、substitute
、quo
, sym
, enquo
, ensym
, ... 什么都没用(你可以在这里看到我不太掌握这些)。
我可以用什么表达式替换第二个代码块中的 x=everything()
行以使该函数起作用?
版本:
- tidyselect 版本 1.0.0
- rlang 版本 0.4.5
- dplyr 版本 0.8.5
我们可以将 everything
包裹在 eval_select
中
bar <- function(x, ...){
xloc <- tidyselect::eval_select(expr(c(x, ...)), data = iris)
if(length(xloc) == 0) {
xloc <- tidyselect::eval_select(expr(everything()), data = iris)
}
xloc
}
bar(1:2)
#Sepal.Length Sepal.Width
# 1 2
bar(NULL)
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
或者我们可以在 expr
中设置 if/else
条件
bar <- function(x, ...) {
x1 <- expr(c(if(is_null(x)) everything() else x, ...))
tidyselect::eval_select(x1, data = iris)
}
bar(everything())
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
bar(NULL)
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
首先你需要通过{{
传递x
,否则参数不能被tidyselect检查,某些功能将无法正常工作。然后你可以给它一个默认值 everything()
:
foo <- function(x = everything(), ...) {
eval_select(expr(c({{ x }}, ...)), data = iris)
}
foo(everything())
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 2 3 4 5
foo()
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 2 3 4 5
如果您出于某种原因不能使用默认参数,请手动解除 everything()
然后使用 !!
:
强制使用它
foo <- function(x = NULL, ...) {
x <- enquo(x)
if (quo_is_null(x)) {
x <- expr(everything())
}
eval_select(expr(c(!!x, ...)), data = iris)
}
我在某些函数中使用了 tidyselection,我必须将第一个参数与省略号连接起来,因为它可能是需要特定处理的特定 class。
正常行为是这样的:
foo = function(x, ...){
xloc = eval_select(expr(c(x, ...)), data = iris)
return(xloc)
}
foo(everything())
当 x
为 NULL
时,我想将 everything()
作为默认值(我不能将它直接放在 header 中原因).
很遗憾,不允许使用此语法:
bar = function(x, ...){
if(is_null(x))
x=everything() #throws an error
xloc = eval_select(expr(c(x, ...)), data = iris)
return(xloc)
}
bar(NULL)
# Error: `everything()` must be used within a *selecting* function.
# i See <https://tidyselect.r-lib.org/reference/faq-selection-context.html>.
我尝试用我知道的所有 "mystic" 函数包装 everything()
:parse
、deparse
、call
、substitute
、quo
, sym
, enquo
, ensym
, ... 什么都没用(你可以在这里看到我不太掌握这些)。
我可以用什么表达式替换第二个代码块中的 x=everything()
行以使该函数起作用?
版本:
- tidyselect 版本 1.0.0
- rlang 版本 0.4.5
- dplyr 版本 0.8.5
我们可以将 everything
包裹在 eval_select
bar <- function(x, ...){
xloc <- tidyselect::eval_select(expr(c(x, ...)), data = iris)
if(length(xloc) == 0) {
xloc <- tidyselect::eval_select(expr(everything()), data = iris)
}
xloc
}
bar(1:2)
#Sepal.Length Sepal.Width
# 1 2
bar(NULL)
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
或者我们可以在 expr
if/else
条件
bar <- function(x, ...) {
x1 <- expr(c(if(is_null(x)) everything() else x, ...))
tidyselect::eval_select(x1, data = iris)
}
bar(everything())
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
bar(NULL)
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 2 3 4 5
首先你需要通过{{
传递x
,否则参数不能被tidyselect检查,某些功能将无法正常工作。然后你可以给它一个默认值 everything()
:
foo <- function(x = everything(), ...) {
eval_select(expr(c({{ x }}, ...)), data = iris)
}
foo(everything())
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 2 3 4 5
foo()
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 2 3 4 5
如果您出于某种原因不能使用默认参数,请手动解除 everything()
然后使用 !!
:
foo <- function(x = NULL, ...) {
x <- enquo(x)
if (quo_is_null(x)) {
x <- expr(everything())
}
eval_select(expr(c(!!x, ...)), data = iris)
}