4

One of my in-progress functions calls grep() with value = TRUE hard-coded. I'd like to pass all of the further arguments except value to grep() through with .... The two functions below are tests I've done so far, neither of which gets the job done.

What is the best way to exclude one or more further arguments when using ... ?

Practice function 1:

f <- function(pattern, x, ...)
{
    dots <- list(...)
    if('value' %in% names(dots)) 
        dots <- dots[!grepl('value', names(dots))]
    grep(pattern, x, value = TRUE, ...)
}

XX <- c('bct', 'abc', 'fds', 'ddabcff', 'jkl')    
## test f()
f('abc', XX, value = TRUE) ## to test the error if user enters 'value' argument
# Error in grep(pattern, x, value = TRUE, ...) : 
#     formal argument "value" matched by multiple actual arguments
f('abc', XX, invert = TRUE)
# [1] "bct" "fds" "jkl"
f('ABC', XX, ignore.case = TRUE)
# [1] "abc"     "ddabcff"

Practice function 2:

h <- function(pattern, x, ...) x[grep(pattern, x, ...)]    
## test h()
h('abc', XX, value = TRUE)
# [1] NA NA
h('abc', XX, invert = TRUE)
# [1] "bct" "fds" "jkl"
h('ABC', XX, ignore.case = TRUE)
# [1] "abc"     "ddabcff"
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
  • Is there a problem with including value as a named parameter? – Dason May 25 '14 at 14:11
  • Yes, it must be set to TRUE. I'll post the snippet from the function I'm writing. – Rich Scriven May 25 '14 at 14:16
  • 2
    A workaround could be to change the last line in your `f` to `do.call("grep", c(list(pattern = pattern), list(x = x), value = TRUE, dots))` where in "dots" you have excluded "value" argument. – alexis_laz May 25 '14 at 14:16
  • @alexis_laz, that seems to work nicely. – Rich Scriven May 25 '14 at 14:32
  • @alexis_laz, would you mind posting an answer? I'm having a bit of trouble implementing it given the snippet I provided. – Rich Scriven May 25 '14 at 15:17
  • You can check out the `functional` library. If you use `Curry` thou it will have a similar problem to `f`. Also see http://stackoverflow.com/questions/2228544/higher-level-functions-in-r-is-there-an-official-compose-operator-or-curry-fun and http://stackoverflow.com/questions/5354364/currying-functions-in-r – jdharrison May 25 '14 at 15:25

2 Answers2

4

You can combine Curry with do.call:

require(functional)
f <- function(pattern, x, ...)
{
  dots <- list(...)
  dots <- dots[!grepl('value', names(dots))]
  do.call(Curry(grep, pattern=pattern, x=x, value=TRUE), dots)
}

Curry provides the known arguments, and dots supplies everything other than "value" in ....

Matthew Lundberg
  • 42,009
  • 6
  • 90
  • 112
2

One way is to just make value a named parameter but ignore the input - that way it will never be a part of the dots to begin with.

f <- function(pattern, x, value = "hahaThisGetsIgnored", ...){
   grep(pattern, x, value = TRUE, ...)
}

You can also use the idea in the answer @MatthewLundberg gave but by doing the argument manipulation without Curry so you don't need the functional package

f <- function(pattern, x, ...){
  dots <- list(...)
  # Remove value from the dots list if it is there
  dots$value <- NULL
  args <- c(list(pattern = pattern, x = x, value = TRUE), dots)
  do.call(grep, args)
}
Dason
  • 60,663
  • 9
  • 131
  • 148