创建一个可以处理列表或符号作为输入参数的函数

问题描述 投票:0回答:1

我创建了一个函数 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)
r dplyr rlang
1个回答
0
投票

函数

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

© www.soinside.com 2019 - 2024. All rights reserved.