使用非标准评估将值放入函数或列表中

时间:2015-11-23 03:34:57

标签: r httr

如果按如下方式定义列表:list(param = "value1"),则结果为:

> list(param = "value1")
#$param
#[1] "value1"

我尝试定义一个新的运算符%!=%,以便我可以按如下方式定义一个列表:list(param %!=% "value1")我希望结果为:

> list(param %!=% "value1")
#$param.ne
#[1] "value1"

作为背景,我正在为从数据库中提取数据的RESTful API编写R包装器。当您发出请求时,您可以告诉API返回与参数值param1 = value1匹配的结果 - 这将直接包含在GET请求的查询字符串中。

但是,API还允许您提取与参数值不匹配的结果:param != value1。将!=放入请求的查询字符串会出现问题。该API旨在使用param.ne = value1代替param != value1

目前,我尝试使用非标准评估中的一些元素来实现这一目标:

`%!=%` = function(query, value) {
  query = deparse(substitute(query))
  query = paste0("`", query, ".ne", "`", "=", "\"", value, "\"")

  parse(text = query)
}

此函数将使用非标准评估确定查询类型(paramparam2param3等),将查询转换为字符串,添加{{ 1}}到最后并将其作为表达式发回。

但是,如果我尝试.ne,那么结果将是:

list(eval(param1 %!=% "value1"))

有没有一种简单的方法来实现上述目标?

编辑: 根据以下帖子,还有一个问题:
反正是否适应上述使用具有默认参数的函数?例如:

> list(eval(address %!=% "value1"))
#[[1]]
#[1] "value1"

我想做类似

的事情
newlist <- function(param1 = "default1", param2 = "default2", ...) 

结果是包含newlist(param2 = "non-default", param3 %!=% "stuff") param1 = "default1"param2 = "non-default"的列表?

1 个答案:

答案 0 :(得分:2)

您最好在list()级别调用时解决此问题,而不是试图干扰参数名称替换。例如,考虑这个函数

newlist <- function(...) {
    dots <- substitute(...())
    op <- sapply(sapply(dots, '[[', 1), deparse)
    car <- sapply(sapply(dots, '[[', 2), deparse)
    cdr <- sapply(sapply(dots, "[[", 3), eval.parent)
    stopifnot(all(op %in% c("==","!=")))
    setNames(as.list(cdr), ifelse(op=="!=", paste0(car, ".ne"), car))
}

newlist(a == "b", c != "d")
# $a
# [1] "b"
# $c.ne
# [1] "d"

这里我们看一下你传递给函数的表达式,并确保它们是==!=,并且可以构建适当的列表。

但如果你真的想使用你的功能,你可以做到

`%!=%` = function(query, value) {
  field = paste0(deparse(substitute(query)), ".ne")
  setNames(list(value), field)
}
a %!=% 5
# $a.ne
# [1] 5

请注意,这将直接返回一个列表。您可以将它们与c

结合使用
c(a %!=% 5, b %!=% "fred")