Gabi
Gabi

Reputation: 1343

How to pass an expression to the filter() verb the tidy way?

I have a way that works and one that does not, and I cannot figure out what's wrong with the latter. Here:

library(tidyverse)
get_these <- c(`Ideal E` = "cut == 'Ideal' & color == 'E'", 
               `Good J` = "cut == 'Good' & color == 'J'")

# This works:
get_these %>% 
  map(rlang::parse_expr) %>% 
  map(function(pick_these) 
    diamonds %>% 
      filter(!!pick_these)) %>% 
  tibble(goods = .) %>% 
  mutate(wat = names(get_these))

# This does not:
tibble(pick_these = get_these %>% 
         map(rlang::parse_expr)) %>% 
  mutate(wat = names(get_these), 
         goods = list(diamonds)) %>% 
  mutate(goods = pmap(.l = dplyr::select(., 
                                         goods, 
                                         pick_these), 
                      .f = function(goods, pick_these) {
                        goods %>% filter(!!pick_these)
                      })) %>% 
  dplyr::select(goods, wat)

Upvotes: 2

Views: 326

Answers (2)

Gabi
Gabi

Reputation: 1343

Actually, this works:

tibble(pick_these = get_these %>% 
         map(rlang::parse_expr)) %>% 
  mutate(wat = names(get_these), 
         goods = list(diamonds)) %>% 
  mutate(goods = pmap(.l = dplyr::select(., 
                                         goods, 
                                         pick_these), 
                      .f = function(goods, pick_these) {
                        goods %>% filter(rlang::eval_tidy(pick_these))
                      })) %>% 
  dplyr::select(goods, wat)

So the trick is to use rlang::eval_tidy() instead of !!. I had no idea before reading @akrun's answer, and I still have no idea why !! does not work in this context.

Upvotes: 1

akrun
akrun

Reputation: 887691

We can select the columns of interest and extract the components with ..1, ..2 (or .x, .y - if there are only 2 columns)

library(dplyr)
library(tibble)
library(purrr)
tibble(pick_these = get_these %>% 
         map(rlang::parse_expr)) %>% 
  mutate(wat = names(get_these), 
         goods = list(diamonds))  %>% 
         mutate(goods = pmap(select(., goods, pick_these), ~ {
                                     ..1 %>% 
                                          filter(rlang::eval_tidy( ..2))

                                         })) %>%
                                          dplyr::select(goods, wat)

# A tibble: 2 x 2
#  goods                 wat    
#  <list>                <chr>  
#1 <tibble [3,903 × 10]> Ideal E
#2 <tibble [307 × 10]>   Good J 

Upvotes: 2

Related Questions