如何根据可变数量的 tidyeval 输入创建 data.frame
How can I create a data.frame based on variable number of tidyeval inputs
首先对这个有点不详尽的标题表示歉意
我有一个闪亮的应用程序,用户可以在其中下载许多可能的数据集之一,并且对于某些列可以执行过滤器以生成 data.frame 输出
我想标准化代码而不考虑下载的数据集
问题是列名因数据集而异,我希望过滤的列数会有所不同
就创建输入而言,我已经采用 使用 tidyeval 方法。但是,我在输出时遇到了困难,而不必根据可以过滤的列数求助于很多 if else 语句
这是一个基于数据集的 (non-shiny) 示例,其中我有 2 个可过滤的列,一个始终需要的值列和一个在最终输出中不需要的列
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
您似乎将输入存储在单独的变量中,建议您预先知道将对多少列进行操作(除非这些列来自动态生成的 UI)。无论如何,我建议您将输入保留在一个对象(希望长度与 my_cols
相同,否则您可以对输入列表进行子集化以匹配 my_cols
向量的长度)。然后你可以准备一个quosures列表并将它们拼接成filter
和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)
如果你把它放在一个函数里,记得使用enquos()
首先对这个有点不详尽的标题表示歉意
我有一个闪亮的应用程序,用户可以在其中下载许多可能的数据集之一,并且对于某些列可以执行过滤器以生成 data.frame 输出
我想标准化代码而不考虑下载的数据集
问题是列名因数据集而异,我希望过滤的列数会有所不同
就创建输入而言,我已经采用
这是一个基于数据集的 (non-shiny) 示例,其中我有 2 个可过滤的列,一个始终需要的值列和一个在最终输出中不需要的列
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
您似乎将输入存储在单独的变量中,建议您预先知道将对多少列进行操作(除非这些列来自动态生成的 UI)。无论如何,我建议您将输入保留在一个对象(希望长度与 my_cols
相同,否则您可以对输入列表进行子集化以匹配 my_cols
向量的长度)。然后你可以准备一个quosures列表并将它们拼接成filter
和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)
如果你把它放在一个函数里,记得使用enquos()