Reputation: 89
I'm trying to filter a data.frame with filter()
function from the package dplyr
. The main problem here is that I want to use a vector for the conditions.
For example
library(dplyr)
conditions <- c("Sepal.Width<3.2","Species==setosa")
DATA <- iris %>%
filter(conditions) #This doesnt work, of course.
Is there any function that would take
conditions <- c("Sepal.Width<3.2","Species==setosa")
as an input and give me
Sepal.Width<3.2 & Species==setosa
as an output? I though about using eval(parse...)
with sapply
and maybe paste0()
to add the &
, but can't make it work.
Any help would be aprecciated.
Upvotes: 4
Views: 341
Reputation: 34751
A tidyeval way would be to use rlang::parse_exprs()
.
library(dplyr)
conditions <- c("Sepal.Width < 3.2", "Species == 'setosa'")
iris %>%
filter( !!! rlang::parse_exprs(conditions))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 4.9 3.0 1.4 0.2 setosa
2 4.6 3.1 1.5 0.2 setosa
3 4.4 2.9 1.4 0.2 setosa
4 4.9 3.1 1.5 0.1 setosa
5 4.8 3.0 1.4 0.1 setosa
6 4.3 3.0 1.1 0.1 setosa
7 5.0 3.0 1.6 0.2 setosa
8 4.8 3.1 1.6 0.2 setosa
9 4.9 3.1 1.5 0.2 setosa
10 4.4 3.0 1.3 0.2 setosa
11 4.5 2.3 1.3 0.3 setosa
12 4.8 3.0 1.4 0.3 setosa
Upvotes: 2
Reputation: 33613
Here is a way:
conditions <- c("Sepal.Width<3.2","Species=='setosa'")
# note the small change here: ↑ ↑
DATA <- iris %>%
filter(eval(parse(text = paste(conditions, collapse = "&"))))
> DATA
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 4.9 3.0 1.4 0.2 setosa
2 4.6 3.1 1.5 0.2 setosa
3 4.4 2.9 1.4 0.2 setosa
4 4.9 3.1 1.5 0.1 setosa
5 4.8 3.0 1.4 0.1 setosa
6 4.3 3.0 1.1 0.1 setosa
7 5.0 3.0 1.6 0.2 setosa
8 4.8 3.1 1.6 0.2 setosa
9 4.9 3.1 1.5 0.2 setosa
10 4.4 3.0 1.3 0.2 setosa
11 4.5 2.3 1.3 0.3 setosa
12 4.8 3.0 1.4 0.3 setosa
Upvotes: 3
Reputation: 40171
There are multiple issues. First, you need to quote inside quotation for the second condition:
conditions <- c("Sepal.Width < 3.2", "Species == 'setosa'")
Then, you need to specify the association between the two conditions. Here, I assumed an &
. Then you can use eval(parse(...))
:
iris %>%
filter(eval(parse(text = paste(conditions, sep = "&"))))
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
7 4.6 3.4 1.4 0.3 setosa
8 5.0 3.4 1.5 0.2 setosa
9 4.4 2.9 1.4 0.2 setosa
10 4.9 3.1 1.5 0.1 setosa
On the other hand, I think it is always important to quote @Martin Mächler to warn about the potential problems associated with this approach:
The (possibly) only connection is via parse(text = ....) and all good R programmers should know that this is rarely an efficient or safe means to construct expressions (or calls). Rather learn more about substitute(), quote(), and possibly the power of using do.call(substitute, ......).
Upvotes: 4