First of all apologies for the somewhat uninformative title
I have a shiny app where a user downloads one of many possible datasets and for some columns can perform a filter to produce a data.frame output
I want to standardize the code irrespective of the dataset downloaded
The problem is that the column names differ by dataset and there will be a variable number of columns I wish to filter on
As far as creating inputs are concerned, I have adapted this solution using a tidyeval approach. However, I am having difficulty with the output without having to resort to a lot of if else statements based on number of columns that can be filtered on
Here is an (non-shiny) example based on a dataset where I have 2 filterable columns, a Value column which is always required and one column unwanted in the final output
library(tidyverse)
## desired columns
my_cols <- c("col 1", "another col")
# selected input
input_1 <- c("A","B")
input_2 <- c("Z")
l <- list(`col 1` = rep(c("A","B","C"),times=3), `another col` =
rep(c("X","Y","Z"),each=3), Value = c(1:9),`Unwanted 1`=(9:1))
df <- as_tibble(l)
# this creates the right number of correctly-named columns
for (i in seq_along(my_cols)) {
assign(paste0("col_", i), sym(my_cols[i]))
}
## This produces output but wish to adapt
## to varying number of columns
df %>%
filter(!!col_1 %in% input_1) %>%
filter(!!col_2 %in% input_2) %>%
select(!!col_1, !!col_2, Value)
# `col 1` `another col` Value
# <chr> <chr> <int>
# 1 A Z 7
# 2 B Z 8
So it is the last piece of code I wish to adapt to take account of the variable length of my_cols
TIA
You seem to store input in separate variables, with suggests you know up front how many columns will be operated on (unless those are coming from dynamically generated UI).Anyways, I suggest you keep inputs in one object as well (hopefully same length as my_cols
, otherwise you could subset the input list to match the length of the my_cols
vector). Then you can prepare a list of quosures and splice them into filter
and select
.
library(tidyverse)
library(rlang)
## desired columns
my_cols <- c("col 1", "another col")
# selected input
input_1 <- c("A","B")
input_2 <- c("Z")
input_3 <- NULL # ui handle that is not used for this dataset
l <- list(`col 1` = rep(c("A","B","C"),times=3), `another col` =
rep(c("X","Y","Z"),each=3), Value = c(1:9),`Unwanted 1`=(9:1))
df <- as_tibble(l)
# make a list of inputs
l_input <- list(input_1, input_2, input_3)[seq_along(my_cols)]
# make a list of expression quosures. Make sure you use enquos if inside function
l_expr <- mapply(function(x,y) quos(!!sym(x) %in% !!y), my_cols, l_input, USE.NAMES = F)
# splice into filter and select
df %>% filter(!!!l_expr) %>% select(!!!syms(my_cols), Value)
If you put this inside a function, remember to use enquos()