2

I want to use subset within another function but to pass on the non-standard evaluation arguments from the top-level function. The following is non-working code, but outlines the idea:

foo_1 <- function(x, mysubset) 
{
  # some deparse, substitute etc. magic here ??
  subset(x, subset)
}
foo_1(ansombe, x1 > 5)

I want this to get the same results as for subset(ansombe, x1 > 5). Also, I want the same to work when the argument is passed on to a deeper level, i.e.

foo_2 <- function(x, mysubset) 
{  
  # some deparse, substitute etc. magic here ??
  foo_1(x, mysubset)
}
foo_2(ansombe, x1 > 5)

Here also I want the same result as above.

What I have tried so far

I tried a substitute-deparse, eval-parse combination, like

foo_1 <- function(x, mysubset)
{
  tx <- deparse(substitute(mysubset))
  subset(x, eval(parse(text=tx)))
}
foo_1(anscombe, x1 >5)

This is fine, but how do I go on for foo_2 now?

Also, I remember the dictum by Thomas Lumley:

If the answer is parse() you should usually rethink the question. -- Thomas Lumley (R-help, February 2005)

So, I was wondering if there is a better approach than an eval-parse combination.? Any ideas?

PS. This question is similar but does not include the deeper nesting: Pass subset argument through a function to subset

PPS: Maybe it is fruitful applying the . function from plyr, but I don't know how...

Community
  • 1
  • 1
Mark Heckmann
  • 10,943
  • 4
  • 56
  • 88
  • I'm not a big fan of using `subset` when a simple `foo[foo[,1]<5,]` or similar construct will serve. If you can post some **small, reproducible** sample data we can show an easy way to do this. EDIT: like BrodieG did :-) – Carl Witthoft Dec 18 '14 at 15:40

3 Answers3

4

There might be dragons. (But those hide in subset too.)

foo_1 <- function(x, mysubset) 
{ 
  sub <- eval(substitute(mysubset), envir=x, enclos=parent.frame())
  x[sub,]
}

foo_1(iris, Sepal.Length == 5 & Species == "setosa")
#   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#5             5         3.6          1.4         0.2  setosa
#8             5         3.4          1.5         0.2  setosa
#26            5         3.0          1.6         0.2  setosa
#27            5         3.4          1.6         0.4  setosa
#36            5         3.2          1.2         0.2  setosa
#41            5         3.5          1.3         0.3  setosa
#44            5         3.5          1.6         0.6  setosa
#50            5         3.3          1.4         0.2  setosa
Roland
  • 127,288
  • 10
  • 191
  • 288
2

I don't think you can avoid eval, but you can avoid parse. Just reconstruct the call to subset inside your function:

foo_1 <- function(x, mysubset) {
  eval(call("subset", x, substitute(mysubset)), parent.frame())
}
foo_1(mtcars, cyl == 6 & mpg > 20)
#                 mpg cyl disp  hp drat    wt  qsec vs am gear carb
# Mazda RX4      21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
# Mazda RX4 Wag  21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
# Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1    
BrodieG
  • 51,669
  • 9
  • 93
  • 146
2

As long as you delay the evaulation as long as possible, something like this should work

foo_1 <- function(x, mysubset) 
{
  do.call("subset", list(quote(x), substitute(mysubset)))
}

foo_2 <- function(x, mysubset) 
{  
  do.call("foo_1", list(quote(x), substitute(mysubset)))
}

data(anscombe)
foo_1(anscombe, x1 > 5)    
foo_2(anscombe, x1 > 5)

but if you plan on mucking about with mysubset you would need to be more careful.It would help to know exactly why you are doing this.

MrFlick
  • 195,160
  • 17
  • 277
  • 295