R combining expressions from a list of expressions

Viewed 555

I have a data frame, something like:

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

which i pass to a function where i would like to create an expression that looks like:

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

which i'll then pass to dplyr::filter in the following statement

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

Of course i want this function to be general, so i can pass it any data frame with different column labels. This data frame dataF is just an example

In my function I have been able to make a list of expressions where each element is calculated in a loop

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

but i can not work out how to combine them all into one expression.

2 Answers

One option is to gather, paste and create the expression

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"

Or using 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"

It can also be done without going through the expr route

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"

This is a base R solution. It uses Reduce to form the expression's string, then coerces it to a language object with 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"

The question asks for a function that does the above.

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"
Related