我创建了一个函数 select_or_return ,它应该处理列符号和列表作为输入参数。当为其提供列符号时,它会按预期工作。但是,当我提供列表时,遇到与 rlang 包中的 ensym() 函数相关的错误。
如何创建一个可以处理列表或符号作为输入参数的函数?
library(rlang)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
select_or_return <- function(data, x) {
x_sym <- ensym(x)
# If x is a symbol
if (is_symbol(x_sym)) {
return(data %>% select(!!x_sym))
}
# If x is a list
else if (is.list(x)) {
return(x)
}
# For other cases
else {
stop("x must be a symbol representing a column or a list.")
}
}
# Example usage:
# Create a sample dataframe
df <- data.frame(a = 1:5, b = 6:10)
# Use the function with a column name as a symbol
print(select_or_return(df, a))
#> a
#> 1 1
#> 2 2
#> 3 3
#> 4 4
#> 5 5
# Use the function with a list
print(select_or_return(df, list(1,2,3)))
#> Error in `ensym()`:
#> ! Can't convert to a symbol.
#> Backtrace:
#> ▆
#> 1. ├─base::print(select_or_return(df, list(1, 2, 3)))
#> 2. ├─global select_or_return(df, list(1, 2, 3))
#> 3. │ └─rlang::ensym(x)
#> 4. └─rlang::abort(message = message)
函数
ensym
类似于基本 R 的 substitute
(它实际上在内部使用),因为它只是捕获传递给函数调用的符号作为未计算的符号。与 substitute
不同,它不允许将表达式(例如 list(1, 2, 3)
)转换为符号。
用于捕获符号 或 表达式的更通用的 rlang 函数是
enexpr
。然而,这也将以 unevaluated形式捕获传递给
x
的任何内容。一旦被 x
捕获,您就无法测试 enexpr
是否是一个列表,因为它永远不可能是一个列表 - 它只能是一段未评估的代码。
虽然您可以使用
enexpr
编写此函数,但由于您并不总是想使用data
作为评估环境,因此它变得更加复杂。
因此,在基础 R 中完成整个事情可能是最简单的:
select_or_return <- function(data, x) {
x_nm <- deparse(substitute(x))
if(x_nm %in% names(data)) return(data[x_nm])
if(is.symbol(substitute(x)) & !exists(x_nm)) {
stop("x must be a symbol representing a column, or a list.")
}
if(is.list(x)) return(x)
stop("x must be a symbol representing a column, or a list.")
}
测试,我们得到:
df <- data.frame(a = 1:5, b = 6:10)
select_or_return(df, a)
#> a
#> 1 1
#> 2 2
#> 3 3
#> 4 4
#> 5 5
select_or_return(df, list(1,2,3))
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 2
#>
#> [[3]]
#> [1] 3
如果我们传递的符号不代表数据框中的列或调用环境中的列表,我们会收到自己的特定错误消息。
select_or_return(df, d)
#> Error in select_or_return(df, d): x must be a symbol representing a column, or a list.
创建于 2023-08-12,使用 reprex v2.0.2