使用这个玩具函数-只是dplyr::select
:的包装
select_col <- function(df, chosen_col) {
if(is.character(enquo(chosen_col))){
df %>%
select(all_of(chosen_col))
} else {
df %>%
select({{ chosen_col }})
}
}
它所做的是允许选择传递给chosen_col
的列,而不管该列是作为屏蔽为环境变量的数据变量还是作为屏蔽为环保变量的字符串。
这两者都返回相同的东西:
mtcars %>%
select_col(chosen_col = mpg) %>%
head(2)
mpg
Mazda RX4 21
Mazda RX4 Wag 21
mtcars %>%
select_col(chosen_col = "mpg") %>%
head(2)
mpg
Mazda RX4 21
Mazda RX4 Wag 21
虽然select_col
有效,但我想要的是类似这样的东西不起作用:
select_col_desired <- function(df, chosen_col) {
if(is.character(enquo(chosen_col))){
chosen_col <- convert_to_env_variable(chosen_col)
}
df %>%
select({{ chosen_col }})
}
我可以用什么来代替不存在的函数convert_to_env_variable
,使select_col_desired
返回与select_col
相同的东西?
我知道select
已经在函数之外完成了这项工作。
解决方案1:单列
如果你真的想要convert_to_env_variable()
这样的东西,你可以从rlang::enquo()
开始,跳过条件。
select_col_desired <- function(df, chosen_col) {
chosen_col <- enquo(chosen_col)
df %>%
select(!!chosen_col)
}
见鬼,你可以完全跳过enquo()
和!!
:
select_col_desired <- function(df, chosen_col) {
df %>%
select({{ chosen_col }})
}
这是因为;卷曲的";运算符CCD_ 12首先捕获传递给CCD_;在将结果代入其自己的位置之前,在这里作为df
的上下文中的数据变量进行评估。
结果
不管怎样,你都会得到这个:
# With column as unquoted symbol.
mtcars %>%
select_col_desired(chosen_col = mpg) %>%
head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
# With column as string.
mtcars %>%
select_col_desired(chosen_col = "mpg") %>%
head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
解决方案2:任意选择
对于更通用的解决方案,您可以简单地将列作为...
传递给select()
:
select_any_desired <- function(df, ...) {
df %>% select(...)
}
结果
# With column as unquoted symbol.
mtcars %>%
select_col_desired(mpg) %>%
head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
# With column as string.
mtcars %>%
select_col_desired("mpg") %>%
head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
备注
如果您正在编写一个包,您自然需要@import
或限定rlang::enquo()
、magrittr:`%>%`()
和dplyr::select()
等函数;而不是使用CCD_ 21。
步骤1:获取变量的名称
这是通过as.character(substitute(chosen_col))
完成的,我们还想将其保存到步骤2。
varname <- as.character(substitute(chosen_col))
步骤2:分配到不同的环境
可以使用assign(x, value, envir=parent.frame())
进行分配。在这里,使用parent.frame()
作为分配环境是至关重要的,因为我们希望在函数之外进行分配,而默认行为是分配到当前环境。这里的另一个选项是分配给具有envir=globalenv
的全局环境。
这将我们引向
assign(varname, x, envir=parent.frame())
其中CCD_ 26包含我们想要分配的所有内容。将其读作varname <- x
。
放两个步骤
select_col <- function(df, chosen_col) {
if(is.character(enquo(chosen_col))){
x <- df %>%
select(all_of(chosen_col))
} else {
x <- df %>%
select({{ chosen_col }})
}
varname <- as.character(substitute(chosen_col))
assign(varname, x, envir=parent.frame())
x
}
select_col(mtcars, "mpg") %>% head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
head(mpg, 2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
rm(mpg)
select_col(mtcars, mpg) %>% head(2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21
head(mpg, 2)
#> mpg
#> Mazda RX4 21
#> Mazda RX4 Wag 21