Search code examples
rdplyrtidyverseeval

alternatives to eval parse with dplyr


Is there a way to do filter with a string as parameter without using eval(parse())?

library("dplyr")

subset <- "carb == 4"
subset_df <- mtcars %>% filter(eval(parse(text = subset)))

Solution

  • 1) rlang If what you are asking is whether there are counterparts to eval/parse in the tidyverse then, yes, there are. You will also need rlang which is already used by dplyr but dplyr does not export the functions needed so use a library statement to load it.

    library(dplyr)
    library(rlang)
    
    subset <- "carb == 4"
    mtcars %>% filter(eval_tidy(parse_expr(subset)))
    

    giving:

                         mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
    Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
    Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
    Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
    

    1a) This also works:

    mtcars %>% filter(!!parse_quo(subset, .GlobalEnv))
    

    2) sqldf If you are looking for a way to do this without using eval/parse or any direct alternative to it and it is not required to use the tidyverse then sqldf can do that provided subset contains valid SQL which in the case of the question it does.

    library(sqldf)
    subset <- "carb == 4"
    fn$sqldf("select * from mtcars where $subset")
    

    giving:

        mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    1  21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    2  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    3  14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
    4  19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    5  17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    6  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
    7  10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
    8  14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
    9  13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
    10 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
    

    2a) This can also be written in terms of pipes like this:

    mtcars %>% { fn$sqldf("select * from '.' where $subset") }