1

If I define a list as follows: list(param = "value1"), then the result will be:

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

I'm trying to define a new operator %!=% such that I can define a list as follows: list(param %!=% "value1") and I want the result to be:

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

As background, I'm writing an R wrapper for a RESTful API that is pulling data from a database. When you make a request, you can tell the API to return results that match a parameter value param1 = value1 -- this will be included directly in the query string of the GET request.

However, the API also allows you to pull results that do NOT match the parameter value: param != value1. Putting != into the query string of a request presents a problem. The API is designed to use param.ne = value1 in place of param != value1.

Currently I'm trying to do this using some elements from non-standard evaluation:

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

  parse(text = query)
}

This function will figure out the type of query (param, param2, param3, etc) using non-standard evaluation, convert the query to a string, add a .ne to the end and send it back out as an expression.

However, if I try to do list(eval(param1 %!=% "value1")) then the result will be:

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

Is there a simple way to achieve the above?

EDIT: In light of posts below, an additional question:
Is there anyway to adapt the above to work with a function that has a default parameter? For example:

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

and I wanted to do something like

newlist(param2 = "non-default", param3 %!=% "stuff") 

with the result being a list with param1 = "default1", param2 = "non-default" and param3.ne = "stuff"?

divide_by_zero
  • 997
  • 1
  • 8
  • 20

1 Answers1

2

You're better off tacking this at the list() level call rather than trying to interfere with parameter name replacements. For example, consider this function

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"

Here we look at the expressions you are passing to the function and make sure they are == or != and can build the appropriate list.

But if you really wanted to use your function, you could do

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

Note that this will return a list directly. You can combine them with c

c(a %!=% 5, b %!=% "fred")
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • 1
    could you explain how this, `...()`, little bit of magic forms a list please – user20650 Nov 23 '15 at 04:27
  • 1
    I wish it were easier to search for symbols on this site. Here's a question just about that syntax: http://stackoverflow.com/questions/12523548/confused-by – MrFlick Nov 23 '15 at 04:40
  • Is there anyway to adapt the above to work with a function that has a default parameter? For example, `newlist <- function(param1 = "default1", param2 = "default2", ...)` and I wanted to do something like `newlist(param2 = "non-default", param3 %!=% "stuff")` and the result is a list with `param1 = "default1"`, `param2 = "non-default"` and `param3.ne = "stuff"`? – divide_by_zero Nov 24 '15 at 09:27
  • @hadley Do you have a reference or can you suggest an alternative? – MrFlick Nov 24 '15 at 12:11