Reputation: 1107
I'm writing on a function that should filter each data.table
in a list.
An Example:
library(purrr)
library(magrittr)
library(data.table)
My.List <-
as.data.table(iris) %>%
split(by = "Species")
map(My.List, ~.x[Sepal.Length < 5.5])
That is exactly what I want my result to be. But the function should be very user friendly. This is my desired function and it was even better if I could have multiple conditions separated by a ,
, like in dplyr
's filter
:
myfunction(My.List, Sepal.Length < 5.5)
myfunction(My.List, Sepal.Length < 5.5, Petal.Width > 1)
Upvotes: 0
Views: 246
Reputation: 79228
Technically, this is called Non Standard Evaluation nse
. For the tidyverse, you could check here for the NSE implementation
Anyway to answer your question:
library(tidyverse)
myfunction <- function(lst, ...){
nms <- enquos(...)
map(lst, ~filter(.x, !!!nms))
}
myfunction(My.List, Sepal.Length < 5.5)
myfunction(My.List, Sepal.Length < 5.5, Petal.Width > 1)
If interested in ONLY BASE R functions, you could do:
myfunction <- function(lst, ...){
nms <- substitute(list(...))
lapply(lst, function(x)x[Reduce("&", eval(nms, x)),])
}
Upvotes: 3
Reputation: 173858
Here's a base R equivalent that also does the trick. It uses match.call
to extract the expressions (if there are any), then uses lapply
to iterate through the list, evaluating each expression in the context of each data frame in the list using eval
. This produces a list of logical vectors for each data frame, which are then combined into a single vector with an "&" via Reduce
. This subsets each data frame.
myfunction <- function(.list, ...)
{
mc <- as.list(match.call())[-1]
if(length(mc) == 1) return(.list)
lapply(.list, function(df)
{
conds <- lapply(mc[-1], function(condition) eval(condition, envir = df))
df[Reduce("&", conds),]
})
}
Upvotes: 3