Reputation: 901
I have a list that can be arbitrarily long. For this specific example, it has three elements.
filter_conditions <- list(
list(col = "mpg", value = 17),
list(col = "cyl", value = 2),
list(col = "disp", value = 160)
)
I want to create a function my_func
out of it that can be applied to a dataframe and apply the filter to the respective column specified in each of filter_conditions
elements.
The code below specifies the result I am expecting from calling my_func(mtcars)
in the three-element example above.
library(dplyr)
f1 <- function(x) filter(x, mpg > 17)
f2 <- function(x) filter(x, cyl > 2)
f3 <- function(x) filter(x, disp > 160)
mtcars %>%
f1 %>%
f2 %>%
f3
Again: filter_conditions
can be arbitrarily long and I don't want to write down a call to filter
for each element in filter_conditions
.
Upvotes: 1
Views: 230
Reputation: 269556
1) Define a function myfilter
which takes a data frame and a list which represents a component of filter_conditions
. Then combine them using Reduce
. No packages are used.
myfilter <- function(data, L) data[data[[L$col]] > L$value, ]
Reduce(myfilter, init = mtcars, filter_conditions)
giving:
mpg cyl disp hp drat wt qsec vs am gear carb
Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
2) A different approach is to generate an SQL where
clause and then run it.
library(sqldf)
where.vec <- sapply(filter_conditions, with, sprintf("%s > '%s'", col, value))
where <- paste(where.vec, collapse = " and ")
ix <- fn$sqldf("select rowid from mtcars where $where")$rowid
mtcars[ix, ]
If we know that the values are all numeric (as is the case in the example in the question) then we could omit the single quotes in the definition of where.vec
.
Upvotes: 4
Reputation: 5650
You can create a composed function with the tidyverse:
library(tidyverse)
my_func <-
compose(!!!map(filter_conditions,
function(f) function(dat) filter(dat, !!sym(f$col) > f$value)))
mtcars %>%
my_func()
Upvotes: 2