【问题标题】:Function argument as value or column name for data.table作为 data.table 的值或列名的函数参数
【发布时间】:2021-12-13 23:18:16
【问题描述】:

我希望我的函数能够采用值或列名。如何使用 data.table 做到这一点?

library(data.table)

df <- data.table(a = c(1:5), 
                 b = c(5:1), 
                 c = c(1, 3, 5, 3, 1))

myfunc <- function(val) {
  df[a >= val]
}

# This works:
myfunc(2)

# This does not work: 
myfunc("c")

如果我将函数定义为:

myfunc <- function(val) {
  df[a >= get(val)]
}

# This doesn't work:
myfunc(2)

# This works: 
myfunc("c")

解决这个问题的最佳方法是什么?

编辑:明确地说,我希望结果与以下内容相同:

# myfunc(2)
df %>%
  filter(a >= 2)

# myfunc("c")
df %>%
  filter(a >= c)

编辑: 感谢大家的回复,我想我最喜欢 dww 的回答。 我希望它像在 dplyr 中一样简单,我可以做到:

myfunc <- function(val) {
  df %>%
    filter(a >= {{val}})
}

# Both work:
myfunc(2)
myfunc(c)

【问题讨论】:

  • 只要你确定你只会使用数值或列名来调用函数,那么你可以做类似df[a &gt;= {if (is.numeric(val)) val else get(val)}]

标签: r data.table


【解决方案1】:

如果您构建并解析整个表达式,那么您可以对其进行整体评估。例如

myfunc <- function(val) {
  df[eval(parse(text=paste("a >= ", val)))]
}

虽然依赖一个允许您在同一个参数中混合值和变量名的函数可能是危险的。特别是在您实际上想要匹配字符值而不是变量名的情况下。如果你传入整个表达式,你可以这样做

myfunc <- function(expr) {
  expr <- substitute(expr)
  df[eval(expr)]
}

myfunc(a>=3)
myfunc(a>=c)

【讨论】:

    【解决方案2】:

    这个问题实际上并没有定义期望的行为,所以我们假设 df 必须是一个 data.table 并且如果传递了一个字符串,那么应该返回该名称的列,如果传递了一个数字,那么那些 @ 987654321@ 列超过应该返回的数字。

    为字符和默认值定义一个 S3 泛型和方法。

    myfunc <- function(x, data = df) UseMethod("myfunc")
    myfunc.character <- function(x, data = df) data[[x]]
    myfunc.default <- function(x, data = df) data[a > x]
     
    myfunc(2)
    ##    a b c
    ## 1: 3 3 5
    ## 2: 4 2 3
    ## 3: 5 1 1
    
    myfunc("c")
    ## [1] 1 3 5 3 1
    

    【讨论】:

      猜你喜欢
      • 2020-07-01
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多