rnorouzian
rnorouzian

Reputation: 7517

subset from a list of data.frames in R

In my function below ... represents any vectors (e.g., numeric or character etc.) named by the user. For example, a user might define age = 1:3 and prof = c("med", "low", "med"). These extra vectors are added to a data.frame called out.

I was wondering if there is a way I could create a new argument called extract to allow user to subset from the final output h.

For example, if a user wants to subset age == 2 or age == 2 & prof == "low" the corresponding match from the output is returned by use of extract = age == 2 & prof == "low"?

foo <- function(d, per, ...){ ## Add a new argument called `extract`

 out <- data.frame(d, ...)

h <- split(out, rep(seq_along(per), per))  ## `extract` should subset from `h`
return(h)
}
# Example of use:
foo(d = 2:4, per = 1:2, age = 1:3, prof = c("med", "low", "med"))

Upvotes: 2

Views: 77

Answers (2)

G. Grothendieck
G. Grothendieck

Reputation: 269644

This does not use any packages nor does it explicitly use eval.

foo2 <- function(d, per, ..., extract = TRUE) {
  out <- data.frame(...)
  h <- split(out, rep(seq_along(per), per))
  s <- substitute(extract)
  lapply(h, function(x) do.call("subset", list(x, s)))
}


foo2(d = 2:4, per = 1:2, age = 1:3, prof = c("med", "low", "med"), extract = age == 2)

Upvotes: 3

akrun
akrun

Reputation: 887128

We can pass the quoted expression in 'extract' and evaluate to filter the rows

library(tidyverse)
foo <- function(d, per, extract, ...){ ## Add a new argument called `extract`

   extract <- rlang::enexpr(extract)
   out <- data.frame(d, ...)


  h <- split(out, rep(seq_along(per), per))  
  map(h, ~ .x %>% 
            filter(!! extract))

 }

foo(d = 2:4, per = 1:2, extract = age == 2, age = 1:3, prof = c("med", "low", "med"))
#$`1`
#[1] d    age  prof
#<0 rows> (or 0-length row.names)

#$`2`
#  d age prof
#1 3   2  low

Or using base R

foo <- function(d, per, extract, ...){ ## Add a new argument called `extract`

   extract <- substitute(extract)
   out <- data.frame(d, ...)


   h <- split(out, rep(seq_along(per), per))  
   lapply(h, function(x) subset(x, subset = eval(extract)))

}

foo(d = 2:4, per = 1:2, extract = age == 2, age = 1:3, prof = c("med", "low", "med"))

Upvotes: 2

Related Questions