Reputation: 7517
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
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
Reputation: 887128
We can pass the quoted expression in 'extract' and eval
uate 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