robertspierre
robertspierre

Reputation: 4441

Error out if filtering for a non-existent level

Given this factor variable:

library(tidyverse)
a <- factor(c(1,1,1,2,2), levels=c(1,2), labels=c("Male", "Female"))

I want this to error out because Females is not a valid level:

a %>% .[.=="Male"|.=="Females"]

How can I do that?

Upvotes: 2

Views: 62

Answers (3)

Edward
Edward

Reputation: 19484

Adding a line involving stopifnot before that command will invoke an error - if that's what you're after.

{
  stopifnot(any(levels(a) %in% "Females"))
  a %>% .[.=="Male"|.=="Females"]
}

Or make it a bit more general:

{
  a1 <- "Male"
  a2 <- "Females"
  
  stopifnot("Error. Invalid factor level." = all(c(a1, a2) %in% levels(a)))
  a %>% .[.==a1|.==a2]
}

Upvotes: 1

Iroha
Iroha

Reputation: 34751

forcats::fct_match() errors when levels aren't present, so you can do:

library(forcats)

a <- factor(c(1,1,1,2,2), levels=c(1,2), labels=c("Male", "Female"))

a %>% .[fct_match(., c("Male", "Females"))]

#> Error in `fct_match()`:
#> ! All `lvls` must be present in `f`.
#> ℹ Missing levels: "Females"

a %>% .[fct_match(., c("Male", "Female"))]

#> [1] Male   Male   Male   Female Female
#> Levels: Male Female

Upvotes: 4

Roland
Roland

Reputation: 132969

You could trace Ops.factor:

trace(Ops.factor, tracer = quote({
  if (nzchar(.Method[1L])) stopifnot("Comparing factor with value not in levels" = 
                                       all(e2 %in% levels(e1)))
  if (nzchar(.Method[2L])) stopifnot("Comparing factor with value not in levels" = 
                                       all(e1 %in% levels(e2)))
}), at = 1, print = FALSE)
#Tracing function "Ops.factor" in package "base"

"Females" == a
#Error in Ops.factor("Females", a) : 
#  Comparing factor with value not in levels

"Female" == a
#[1] FALSE FALSE FALSE  TRUE  TRUE

untrace(Ops.factor)

PS: I would want to test the tracer with some edge cases if I intended to use it in production code.

Upvotes: 3

Related Questions