3

我正试图围绕非标准评估,因为它在rlang包中进行了解释。考虑到这个目标,我的问题是:

如何编写dplyr::select.list()符合 tidy 评估原则的函数?

这是我目前如何编写包装器的示例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)

有没有更干净、更整洁的评估一致的方法来做到这一点?

4

2 回答 2

4

您可以使用 tidyselect 实现后端select()

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"))

请注意,当您不拥有泛型(例如select()由 dplyr 拥有)或类(例如list来自 R 核心)时,实现 S3 方法是不好的做法。

于 2018-02-08T18:24:00.647 回答
0

我认为 dplyr 是为 dfs

使用列表做超级奇怪的事情的原因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]以返回命名元素的列表。

于 2018-02-08T17:38:55.283 回答