R 组合表达式列表中的表达式



我有一个数据框,像这样:

dataF <- data.frame(YEAR = 1996, MONTH = 10, LOCATION = "RIVER",stringsAsFactors = F)

我传递给一个函数,我想在其中创建一个如下所示的表达式:

YEAR == 1966 & MONTH == 10 & LOCATION == "RIVER"

然后我将在以下语句中传递给 dplyr::filter

dataSet %>% dplyr::filter(YEAR == 1966 & MONTH == 10 & LOCATION == "RIVER")

当然,我希望这个函数是通用的,所以我可以传递任何具有不同列标签的数据框。此数据框dataF只是一个示例

在我的函数中,我已经能够制作表达式列表 其中每个元素都在循环中计算

cats <- names(dataF)
expres <- list()
for (i in 1:length(cats)) {
expres[[i]] <- rlang::expr(!!(rlang::sym(cats[i])) == !!(dataF[[cats[i]]]))
}

但是我无法弄清楚如何将它们全部组合成一个表达式。

一种选择是gatherpaste并创建表达式

library(dplyr)
library(tidyr)
library(magrittr)
library(stringr)
out <- gather(dataF) %>% 
mutate(value = sprintf('"%s"', value)) %>% 
unite(key, key, value, sep='==') %>% 
summarise(key = str_c(key, collapse=' & ')) %>% 
pull(key) %>% 
parse(text = .) %>% 
extract2(1)
out
#YEAR == "1996" & MONTH == "10" & LOCATION == "RIVER"
str(out)
#language YEAR == "1996" & MONTH == "10" & LOCATION == "RIVER"

或使用imap

library(purrr)
out2 <- imap(dataF, ~  deparse(rlang::expr(!!(rlang::sym(.y)) ==  !!.x ) )) %>% 
reduce(~ str_c(.x,.y,  sep=" & ")) %>% 
parse(text = .) %>%
extract2(1)
out2
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
str(out2)
#language YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"

也可以在不经过expr路线的情况下完成

imap(dataF, ~ if(is.character(.x)) sprintf('%s == "%s"', .y, .x)
else sprintf('%s == %s', .y, .x)) %>%
reduce(str_c,sep =" & ") %>%
parse(text = .) %>%
extract2(1)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"

这是一个基本的 R 解决方案。它使用Reduce来形成表达式的字符串,然后将其强制转换为具有str2lang的语言对象。

f <- function(x, y) {
i <- sapply(y, is.character)
y[i] <- paste0("'", y[i], "'")
paste(x, y, sep = ' == ', collapse = ' & ')
}
expr <- Reduce(f, list(names(dataF), unname(as.list(dataF))))
str2lang(expr)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
str(str2lang(expr))
# language YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"

该问题要求一个执行上述操作的函数。

df2lang <- function(DF){
f <- function(x, y) {
i <- sapply(y, is.character)
y[i] <- paste0("'", y[i], "'")
paste(x, y, sep = ' == ', collapse = ' & ')
}
expr <- Reduce(f, list(names(DF), unname(as.list(DF))))
str2lang(expr)
}
df2lang(dataF)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
dataF2 <- data.frame(This = 1996, That = "A", x = "RIVER",stringsAsFactors = F)
df2lang(dataF2)
#This == 1996 & That == "A" & x == "RIVER"

最新更新