我正试图围绕非标准评估,因为它在rlang包中被解释。考虑到这个目标,我的问题是:
如何编写符合整洁评估原则的
dplyr::select.list()
函数?
以下是我目前如何围绕dplyr::select()
编写包装器的示例:
select_wrapper <- function(x, ...) {
vars <- rlang::quos(...)
dplyr::select(x, !!!vars)
}
适用于数据框,例如,
> select_wrapper(mtcars, cyl, mpg)
> ## cyl mpg
> ## Mazda RX4 6 21.0
> ## Mazda RX4 Wag 6 21.0
> ## Datsun 710 4 22.8
> ## Hornet 4 Drive 6 21.4
> ## Hornet Sportabout 8 18.7
> ## Valiant 6 18.1
但不在名单上:
attr(mtcars, "test") <- "asdf"
mtcars_list <- attributes(mtcars)
select_wrapper(mtcars_list, row.names, test)
> ## 1: c("mpg", "cyl", "disp", "hp", "drat", "wt", "qsec", "vs", "am", "gear", "carb")
> ## 2: c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", "Volvo 142E")
> ## 3: data.frame
> ## 4: asdf
> ## Selection:
老实说,我不确定上面输出中发生了什么......它返回一个交互式提示,要求我选择我想要的元素。这不是很理想,imo。
无论如何,我想要完成的是select.list()
函数,它返回我通过非标准评估选择的命名元素的列表。这是我的解决方案,但感觉太黑了:
listdf <- function(x) {
as.data.frame(lapply(x, function(x) I(list(x))))
}
dflist <- function(x) {
x <- lapply(x, unlist, recursive = FALSE)
lapply(x, unclass)
}
select.list <- function(x, ...) {
dots <- rlang::quos(...)
if (length(dots) == 0L) return(list())
x <- listdf(x)
dflist(dplyr::select(x, !!!dots))
}
library(dplyr)
attr(mtcars, "test") <- "asdf"
select(attributes(mtcars), test, row.names)
是否有更清洁,更整洁的方法来做到这一点?
答案 0 :(得分:2)
您可以使用实现select()
后端的tidyselect:
select2 <- function(.x, ...) {
vars <- rlang::names2(.x)
vars <- tidyselect::vars_select(vars, ...)
.x[vars]
}
x <- list(a = 1, b = 2)
select2(x, dplyr::starts_with("a"))
请注意,当您不拥有泛型(例如dplyr拥有的select()
)或类(例如list
)时,实施S3方法是不好的做法。 R核心)。
答案 1 :(得分:0)
select
使用列表做超级奇怪的事情的原因是因为它并没有真正做到这一点。我甚至不确定为什么会发生这种情况(我曾经遇到过这个交互式列表的事情而且太混乱了。)
[
为select
但是[
需要字符串。所以你的问题实际上是将裸参数转换为字符串以便在[
中使用:
library(tidyverse)
l <- letters
names(l) <- letters
l
select.list <- function(x, ...) {
vars <- rlang::quos(...) %>% map(quo_text) %>% unlist()
x[vars]
}
select.list(l, a, b)
a b
"a" "b"
在这里,quos
返回一个quosores列表;为此,我映射quo_text
将每个元素从一个quosure转换为一个字符串,然后将这些元素取消列出。然后,您可以直接在列表上调用[
,x[vars]
以返回指定元素的列表。