Conditional filtering using tidyverse

I want to filter my data frame based on a variable that may or may not exist. As an expected result, I want df to be filtered (if it has a filter variable) or the original, unfiltered df (if this variable is missing).

Here is a minimal example:

library(tidyverse) df1 <- tribble(~a,~b, 1L,"a", 0L, "a", 0L,"b", 1L, "b") df2 <- select(df1, b) 

Filtering on df1 returns the desired result, filtered tibet.

 filter(df1, a == 1) # A tibble: 2 x 2 ab <int> <chr> 1 1 a 2 1 b 

But the second causes an error (presumably), since the variable is not in df.

 filter(df2, a == 1) Error in filter_impl(.data, quo) : Evaluation error: object 'a' not found. 

I tried filter_at , which would be an obvious choice, but it throws an error if there is no variable that matches the task.

 filter_at(df2, vars(matches("a")), any_vars(. == 1L)) Error: `.predicate` has no matching columns 

So my question is: is there a way to create conditional filtering that gives the expected result, preferably within tidyverse?

+5
source share
2 answers

As noted in the comments of @ docendo-discimus , the following solutions work. I also added rlang::has_name instead of "a" %in% names(.) .

This Q & A contains the original idea: Conditionally apply the piping pitch depending on the external value .

 df1 %>% filter(if(has_name("a")) a == 1 else TRUE) # A tibble: 2 x 2 ab <int> <chr> 1 1 a 2 1 b df2 %>% filter(if(has_name("a")) a == 1 else TRUE) # A tibble: 4 x 1 b <chr> 1 a 2 a 3 b 4 b 

Or alternatively using {} :

 df1 %>% {if(has_name("a")) filter(., a == 1L) else .} # A tibble: 2 x 2 ab <int> <chr> 1 1 a 2 1 b > df2 %>% + {if(has_name("a")) filter(., a == 1L) else .} # A tibble: 4 x 1 b <chr> 1 a 2 a 3 b 4 b 
+5
source

Something like that?

 # function for expected output foo <- function(x, y){ tmp <- which(colnames(x) %in% y) if(length(tmp) > 0){ filter(x, select(x, tmp) == 1) }else{ df1 } } # run the functions foo(df1, "a") foo(df2, "a") # or df1 %>% foo("a") # A tibble: 2 x 2 ab <int> <chr> 1 1 a 2 1 b df2 %>% foo("a") # A tibble: 4 x 2 ab <int> <chr> 1 1 a 2 0 a 3 0 b 4 1 b 
+1
source

Source: https://habr.com/ru/post/1271733/


All Articles