问题描述
我开始构建“用户友好”的R6类,并希望使函数完成我的类的大部分工作。到目前为止,这是我的结构
x <- X$new()
veggie_cubes <- veggie %>% x$cubesX(ID)
veggie_slices <- veggie %>% x$sliceX(ID)
我的问题是,现在是否可以重写代码,例如:
x <- X$new()
veggie_cubes <- veggie %>% x$cutX(cubesX,ID)
veggie_slices <- veggie %>% x$cutX(sliceX,ID)
函数头应该看起来像:cut(.data,FUN,KEY)
到目前为止,我的想法是像这样写cut
:
cutX= function(.data,KEY)
{
.data %>%
FUN({{ KEY }}) %>%
base::return()
}
唯一可行的方法是调用veggie %>% x$cutX(x$cubesX,ID)
,我不太喜欢将其用作“用户友好”解决方案,我也不很喜欢为此使用字符串。有没有写x$
的方法?
这是简化的R6类:
X <- R6::R6Class(
classname = "X",public = base::list(
cubesX = function(.data,KEY)
{
.data %>%
dplyr::select(!{{ KEY }}) %>%
base::return()
},sliceX = function(.data,KEY)
{
.data %>%
dplyr::select({{ KEY }}) %>%
base::return()
},cutX = function(.data,KEY)
{
.data %>%
FUN( {{ KEY}}) %>%
base::return()
}
)
)
运行示例:
x <- X$new()
iris %>% x$sliceX(Species)
iris %>% x$cubesX(Species)
# with FUN
iris %>% x$cutX(x$sliceX,Species)
iris %>% x$cutX(x$cubesX,Species)
未运行:
iris %>% x$cutX(sliceX,Species)
iris %>% x$cutX(cubesX,Species)
预先感谢:-)
解决方法
以下实现将允许您通过三种方法中的任何一种来调用函数。它通过使用非标准评估来确定FUN
的格式为x$func
还是仅使用裸func
来工作。无论哪种情况,它都使用裸函数名称并构建一个调用以将其转换为self$func
。然后,它只是对该函数求值。
因此,以下R6类在所有测试示例中均按预期工作:
X <- R6::R6Class(
classname = "X",public = base::list(
cubesX = function(.data,KEY)
{
.data %>%
dplyr::select(!{{ KEY }}) %>%
base::return()
},sliceX = function(.data,KEY)
{
.data %>%
dplyr::select({{ KEY }}) %>%
base::return()
},cutX = function(.data,FUN,KEY)
{
if(is.call(substitute(FUN))) {
FUN <- substitute(FUN)
FUN[[2]] <- quote(self)
}
else
FUN <- as.call(list(quote(`$`),quote(self),substitute(FUN)))
eval(as.call(list(FUN,quote(.data),substitute(KEY))))
}
)
)
例如,
x <- X$new()
iris %>% x$cutX(sliceX,Species)
#> Species
#> 1 setosa
#> 2 setosa
#> 3 setosa
#> 4 setosa
#> 5 setosa
#> 6 setosa
#> 7 setosa
#> 8 setosa
#> 9 setosa
#> 10 setosa
#> 11 setosa
#> 12 setosa
#> 13 setosa
#> 14 setosa
#> 15 setosa
#> 16 setosa
#> 17 setosa
#> 18 setosa
#> 19 setosa
#> 20 setosa
#> ...etc