Skip to content

Instantly share code, notes, and snippets.

@tjmahr
Last active March 8, 2024 15:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tjmahr/5ce538f8d1a790134cecf3bd99c000f0 to your computer and use it in GitHub Desktop.
Save tjmahr/5ce538f8d1a790134cecf3bd99c000f0 to your computer and use it in GitHub Desktop.
fct_regex_levels()
fct_regex_levels <- function(xs, patterns) {
  default_levels <- unique(xs)
  which_matches <- default_levels |> 
    lapply(stringr::str_which, patterns) |> 
    unlist()
  stopifnot(
    "Each factor level should have exactly one pattern" =
      all(seq_along(default_levels) %in% which_matches)
  )
  correct_order <- match(seq_along(default_levels), which_matches)
  factor(xs, default_levels[correct_order])
}

xs <- c("final (10)", "initial (18)", "medial (28)")
xs |> 
  factor() |> 
  levels()
#> [1] "final (10)"   "initial (18)" "medial (28)"

xs |> 
  fct_regex_levels(patterns = c("init", "medi", "fina")) |> 
  levels()
#> [1] "initial (18)" "medial (28)"  "final (10)"


library(testthat)
xs <- c("final (10)", "initial (18)", "medial (28)")
ys <- c("initial (18)", "medial (28)", "final (10)")
many_xs <- c(
  "medial (28)", "initial (18)", "medial (28)", "medial (28)", 
  "final (10)", "medial (28)", "medial (28)", "initial (18)", 
  "initial (18)", "initial (18)"
)


expect_levels <- function(object, expected, ...) {
  object |> 
    levels() |> 
    testthat::expect_equal(expected, ...)
}

should_work <- c("init", "medi", "final")
extra_regex <- c("ini", "med", "fin", "whatever") 

unmatched_level <- c("initial", "medial", "whatever") 
double_match <- c("ial", "final", "whatever") 

xs |> 
  fct_regex_levels(should_work) |> 
  expect_levels(ys)

xs |> 
  fct_regex_levels(extra_regex) |> 
  expect_levels(ys)

xs |> 
  fct_regex_levels(unmatched_level) |> 
  expect_error()

xs |> 
  fct_regex_levels(double_match) |> 
  expect_error()

many_xs |> 
  fct_regex_levels(should_work) |> 
  expect_levels(ys)

many_xs |> 
  fct_regex_levels(extra_regex) |> 
  expect_levels(ys)

many_xs |> 
  fct_regex_levels(unmatched_level) |> 
  expect_error()

many_xs |> 
  fct_regex_levels(double_match) |> 
  expect_error()

Created on 2024-03-08 with reprex v2.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment