I'm using dplyr
within a function that takes a data.frame df
as an argument.
At some point, I want to filter based on a vector I've just created named n
. However, this won't work if n
is also the name of a variable in the input data.frame.
library(dplyr)
df <- data.frame(n = c(0L, 0L))
n <- c(1L, 1L)
filter(df, n == 1L)
#> [1] n
#> <0 rows> (or 0-length row.names)
Since the function should work for any dataframe, I would like to avoid this. I tried to use a formula/lazy object associated with the global environment but this returned the same result:
a <- ~ n == 1L
filter_(df, a)
#> [1] n
#> <0 rows> (or 0-length row.names)
a <- lazy(n == 1L)
filter_(df, a)
#> [1] n
#> <0 rows> (or 0-length row.names)
Is there an elegant way to do it?
All the previous answers are outdated because dplyr
now supports rlang
quoting and unquoting semantics.
You can simply use !! n
to prevent n
from being quoted (and interpreted as the column n
).
library(dplyr)
df <- data.frame(n = c(0L, 0L))
n <- c(1L, 1L)
filter(df, !! n == 1L)
## n
## 1 0
## 2 0
Another example using the classic mtcars
:
gear <- 5
# gear == gear is true for all rows!
# this returns the whole dataset
filter(mtcars, gear == gear)
# this works as intended
filter(mtcars, gear == !! gear)
## mpg cyl disp hp drat wt qsec vs am gear carb
## 1 26.0 4 120.3 91 4.43 2.140 16.7 0 1 5 2
## 2 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
## 3 15.8 8 351.0 264 4.22 3.170 14.5 0 1 5 4
## 4 19.7 6 145.0 175 3.62 2.770 15.5 0 1 5 6
## 5 15.0 8 301.0 335 3.54 3.570 14.6 0 1 5 8
Because n
is both a variable name and an object containing values, using interp
from lazyeval and using n
as a value (and not as a variable) appears to do what you want.
library(lazyeval)
filter_(df, interp(~n == 1L, n = n))
n
1 0
2 0
I first tried the more complex
filter_(df, interp(~n == 1L, .values = list(n = n)))
but the simpler version seems to work the same way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With