如何基于可变数量的tidyeval输入创建数据。

时间:2018-07-05 22:42:34

标签: r shiny dplyr tidyeval

首先道歉,因为标题有些无聊

我有一个闪亮的应用程序,用户可以在其中下载许多可能的数据集之一,并且对于某些列可以执行过滤以生成数据。帧输出

我想使代码标准化,而与下载的数据集无关

问题在于列名称因数据集而异,并且我希望过滤的列数将可变

就创建输入而言,我已经使用tidyeval方法修改了this solution。但是,我在输出时遇到困难,而不必基于可过滤的列数而采用很多if else语句

这是一个基于数据集的(非发光)示例,其中我有2个可过滤的列,始终需要使用Value列,而在最终输出中不需要使用1列

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

这是我希望适应于my_cols可变长度的最后一段代码

TIA

1 个答案:

答案 0 :(得分:0)

您似乎将输入存储在单独的变量中,建议您先了解要操作多少列(除非这些列来自动态生成的UI)。无论如何,我建议您也将输入保留在一个对象中(希望与my_cols的长度相同,否则您可以对输入列表进行子集以匹配my_cols向量的长度)。然后,您可以准备一份清单,并将它们拼接为filterselect

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)

如果将其放在函数中,请记住使用enquos()