我想创建一个函数来检查向量中是否包含裸表达式。该函数应该独立于输入数据的情况而工作。
评估各种表达式的一个简单解决方案是使用
tidyselect::eval_select()
。例如。这是一个虚拟函数,用于检查表达式是否为 a
、b
或 c
。
is_abc <- function(...) {
expr <- rlang::expr(c(...))
data <- rlang::set_names(letters)
out <- tidyselect::eval_select(expr, data)
names(out) %in% letters[1:3]
}
is_abc(a, b, z)
#> [1] TRUE TRUE FALSE
is_abc(c(a, b, z))
#> [1] TRUE TRUE FALSE
由 reprex 包于 2023 年 12 月 27 日创建(v2.0.1)
问题是我认为不编辑
tidyselect::eval_select()
(或使用特殊的选择助手)就不可能使其不区分大小写。
is_abc(c(a, B, z))
#> Error in `is_abc()`:
#> ! Can't subset columns that don't exist.
#> ✖ Column `B` doesn't exist.
或者,我可以使用
rlang::enexprs()
获取符号列表,然后在更改大小写或与向量比较时将其转换为字符类型:
is_abc <- function(...) {
exprs <- rlang::enexprs(...)
tolower(exprs) %in% tolower(letters[1:3])
}
is_abc(a, b, z)
#> [1] TRUE TRUE FALSE
is_abc(a, B, z)
#> [1] TRUE TRUE FALSE
由 reprex 包于 2023 年 12 月 27 日创建(v2.0.1)
现在的问题是,这不适用于更复杂的表达式,因为这会将整个表达式转换为字符串:
is_abc(c(a, b, z))
#> [1] FALSE
是否有一个简单的解决方案可以解决这个问题,以便我可以让一个函数在两种情况下都可以工作,而不依赖于输入的情况?
例如:
# desired behaviour
is_abc(c(a, B), z)
#> [1] TRUE TRUE FALSE
你可以在 R 基础上完成所有事情:
is_abc <- function(...) {
args <- as.list(match.call())[-1]
out <- unlist(lapply(args, function(x) {
if(is.call(x)) {
x <- as.list(x)
if(as.character(x[[1]]) != "c") {
stop("is_abc does not know what to do with calls to function '",
as.character(x[[1]]), "'")
}
unlist(lapply(x[-1], as.character))
} else {
as.character(x)
}
}))
toupper(out) %in% c("A", "B", "C")
}
测试:
is_abc(a, b, z)
#> [1] TRUE TRUE FALSE
is_abc(A, b, z)
#> [1] TRUE TRUE FALSE
is_abc(c(a, b, z))
#> [1] TRUE TRUE FALSE
is_abc(c(a, B, z))
#> [1] TRUE TRUE FALSE
is_abc(c(a, B), z)
#> [1] TRUE TRUE FALSE