Title: | Pipe-Friendly Vector Replacement with Case Statements |
---|---|
Description: | Offers a pipe-friendly alternative to the 'dplyr' functions case_when() and if_else(), as well as a number of user-friendly simplifications for common use cases. These functions accept a vector as an optional first argument, allowing conditional statements to be built using the 'magrittr' dot operator. The functions also coerce all outputs to the same type, meaning you no longer have to worry about using specific typed variants of NA or explicitly declaring integer outputs, and evaluate outputs somewhat lazily, so you don't waste time on long operations that won't be used. |
Authors: | Alexander Rossell Hayes [aut, cre, cph] , Patrice Kiener [ctb] (Contributed example for fn_case(), <https://orcid.org/0000-0002-0505-9920>) |
Maintainer: | Alexander Rossell Hayes <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.3.2.9000 |
Built: | 2024-12-07 05:09:19 UTC |
Source: | https://github.com/rossellhayes/incase |
Case statements applying a function to all inputs
fn_case(x, fn, ..., preserve = FALSE, default = NA)
fn_case(x, fn, ..., preserve = FALSE, default = NA)
x |
A vector |
fn |
A function to apply to the left-hand side of each formula in Either a quoted or unquoted function name, an anonymous The function should take two inputs, the first being |
... |
<
|
preserve |
If |
default |
If |
A vector of length 1 or n, matching the length of the logical input or output vectors. Inconsistent lengths will generate an error.
fn_case_fct()
to return a factor and
fn_case_list()
to return a list
fn_switch_case()
, which applies a function to each formula's LHS,
but not x
switch_case()
, a simpler alternative for exact matching
grep_case()
, a simpler alternative for regex pattern matching
in_case()
, a pipeable alternative to dplyr::case_when()
# Replicate switch_case() parties <- sample(c("d", "r", "i", "g", "l"), 20, replace = TRUE) fn_case( parties, fn = `%in%`, "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) # Replicate grep_case() countries <- c( "France", "Ostdeutschland", "Westdeutschland", "Nederland", "Belgie (Vlaanderen)", "Belgique (Wallonie)", "Luxembourg", "Italia" ) fn_case( countries, fn = function(x, pattern, ...) {grepl(pattern, x, ...)}, "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE ) fn_case( countries, fn = ~ grepl(.y, .x), "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE ) # Recode values in a range time <- runif(10, 1, 12) hours <- time %/% 1 minutes <- time %% 1 * 60 hours <- hours %>% if_case(minutes > 32.5, (. + 1) %% 12, .) %>% switch_case(0 ~ 12, preserve = TRUE) minutes %>% fn_case( fn = ~ abs(.x - .y) <= 2.5, 0 ~ "o'clock", 60 ~ "o'clock", 30 ~ "half past", 15 ~ "quarter past", 45 ~ "quarter to", 5 ~ "five past", 10 ~ "ten past", 20 ~ "twenty past", 25 ~ "twenty-five past", 55 ~ "five to", 50 ~ "ten to", 40 ~ "twenty to", 35 ~ "twenty-five to" ) %>% switch_case( "o'clock" ~ paste(hours, .), default = paste(., hours) ) # Replicate vctrs::vec_ptype_abbr() (used for tibble column labels) # Based on a contribution by Patrice Kiener in_herits <- function(x) { fn_case( x, fn = inherits, "factor" ~ "fct", "character" ~ "chr", "numeric" ~ "dbl", "integer" ~ "int", "logical" ~ "lgl", "complex" ~ "cpl", "raw" ~ "raw", "matrix" ~ "mat", "array" ~ "arr", "data.frame" ~ "df", "list" ~ "lst", "function" ~ "fn", default = class(x)[[1]] ) } in_herits(1:3) in_herits(letters[1:3]) in_herits(fn_case)
# Replicate switch_case() parties <- sample(c("d", "r", "i", "g", "l"), 20, replace = TRUE) fn_case( parties, fn = `%in%`, "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) # Replicate grep_case() countries <- c( "France", "Ostdeutschland", "Westdeutschland", "Nederland", "Belgie (Vlaanderen)", "Belgique (Wallonie)", "Luxembourg", "Italia" ) fn_case( countries, fn = function(x, pattern, ...) {grepl(pattern, x, ...)}, "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE ) fn_case( countries, fn = ~ grepl(.y, .x), "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE ) # Recode values in a range time <- runif(10, 1, 12) hours <- time %/% 1 minutes <- time %% 1 * 60 hours <- hours %>% if_case(minutes > 32.5, (. + 1) %% 12, .) %>% switch_case(0 ~ 12, preserve = TRUE) minutes %>% fn_case( fn = ~ abs(.x - .y) <= 2.5, 0 ~ "o'clock", 60 ~ "o'clock", 30 ~ "half past", 15 ~ "quarter past", 45 ~ "quarter to", 5 ~ "five past", 10 ~ "ten past", 20 ~ "twenty past", 25 ~ "twenty-five past", 55 ~ "five to", 50 ~ "ten to", 40 ~ "twenty to", 35 ~ "twenty-five to" ) %>% switch_case( "o'clock" ~ paste(hours, .), default = paste(., hours) ) # Replicate vctrs::vec_ptype_abbr() (used for tibble column labels) # Based on a contribution by Patrice Kiener in_herits <- function(x) { fn_case( x, fn = inherits, "factor" ~ "fct", "character" ~ "chr", "numeric" ~ "dbl", "integer" ~ "int", "logical" ~ "lgl", "complex" ~ "cpl", "raw" ~ "raw", "matrix" ~ "mat", "array" ~ "arr", "data.frame" ~ "df", "list" ~ "lst", "function" ~ "fn", default = class(x)[[1]] ) } in_herits(1:3) in_herits(letters[1:3]) in_herits(fn_case)
Switch-style recoding of values with string pattern matching
grep_case(x, ..., preserve = FALSE, default = NA)
grep_case(x, ..., preserve = FALSE, default = NA)
x |
A vector |
... |
<
|
preserve |
If |
default |
If |
A vector of the same length as x
.
grep_case_fct()
to return a factor and
grep_case_list()
to return a list
fn_case()
, to apply a function other than grepl()
to each case
switch_case()
to recode values with exact matching
in_case()
, a pipeable alternative to dplyr::case_when()
switch()
and grepl()
, which inspired this function
words <- c("caterpillar", "dogwood", "catastrophe", "dogma") grep_case( words, "cat" ~ "feline", "dog" ~ "canine" ) caps_words <- c("caterpillar", "dogwood", "Catastrophe", "DOGMA") grep_case( caps_words, "cat" ~ "feline", "dog" ~ "canine", ignore.case = TRUE ) countries <- c( "France", "Ostdeutschland", "Westdeutschland", "Nederland", "Belgie (Vlaanderen)", "Belgique (Wallonie)", "Luxembourg", "Italia" ) grep_case( countries, "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE )
words <- c("caterpillar", "dogwood", "catastrophe", "dogma") grep_case( words, "cat" ~ "feline", "dog" ~ "canine" ) caps_words <- c("caterpillar", "dogwood", "Catastrophe", "DOGMA") grep_case( caps_words, "cat" ~ "feline", "dog" ~ "canine", ignore.case = TRUE ) countries <- c( "France", "Ostdeutschland", "Westdeutschland", "Nederland", "Belgie (Vlaanderen)", "Belgique (Wallonie)", "Luxembourg", "Italia" ) grep_case( countries, "Deutschland" ~ "Germany", "Belgi(qu)?e" ~ "Belgium", "Nederland" ~ "Netherlands", "Italia" ~ "Italy", preserve = TRUE, ignore.case = TRUE )
Compared to dplyr::if_else()
, this function is easier to use with a pipe.
A vector piped into this function will be quietly ignored.
This allows magrittr dots to be used in arguments without requiring
workarounds like wrapping the function in braces.
if_case(condition, true, false, missing = NA, ...)
if_case(condition, true, false, missing = NA, ...)
condition |
Logical vector |
true , false , missing
|
Values to use for |
... |
Values passed to |
This function is also less strict than dplyr::if_else()
.
If true
, false
, and missing
are different types, they are silently
coerced to a common type.
Where condition
is TRUE
, the matching value from true
;
where it's FALSE
, the matching value from false
;
and where it's NA
, the matching value from missing
.
in_case()
, a pipeable alternative to dplyr::case_when()
switch_case()
, a reimplementation of switch()
dplyr::if_else()
, from which this function is derived
x <- c(1, 2, 5, NA) # if_case() produces the same output as dplyr::if_else() if_case(x > 3, "high", "low", "missing") dplyr::if_else(x > 3, "high", "low", "missing") # if_case() does not throw an error if arguments are not of the same type if_case(x > 3, "high", "low", NA) try(dplyr::if_else(x > 3, "high", "low", NA)) # if_case() can accept a piped input without an error or requiring braces x %>% if_case(. > 3, "high", "low", "missing") try(x %>% dplyr::if_else(. > 3, "high", "low", "missing")) x %>% {dplyr::if_else(. > 3, "high", "low", "missing")} # You can also pipe a conditional test like dplyr::if_else() {x > 3} %>% if_case("high", "low", "missing") {x > 3} %>% dplyr::if_else("high", "low", "missing")
x <- c(1, 2, 5, NA) # if_case() produces the same output as dplyr::if_else() if_case(x > 3, "high", "low", "missing") dplyr::if_else(x > 3, "high", "low", "missing") # if_case() does not throw an error if arguments are not of the same type if_case(x > 3, "high", "low", NA) try(dplyr::if_else(x > 3, "high", "low", NA)) # if_case() can accept a piped input without an error or requiring braces x %>% if_case(. > 3, "high", "low", "missing") try(x %>% dplyr::if_else(. > 3, "high", "low", "missing")) x %>% {dplyr::if_else(. > 3, "high", "low", "missing")} # You can also pipe a conditional test like dplyr::if_else() {x > 3} %>% if_case("high", "low", "missing") {x > 3} %>% dplyr::if_else("high", "low", "missing")
This function allows you to vectorize multiple if_else() statements.
If no cases match, NA is returned.
This function derived from dplyr::case_when()
.
Unlike dplyr::case_when()
, in_case()
supports piping elegantly and
attempts to handle inconsistent types (see examples).
in_case(..., preserve = FALSE, default = NA)
in_case(..., preserve = FALSE, default = NA)
... |
< The LHS must evaluate to a logical vector. Both LHS and RHS may have the same length of either 1 or
|
preserve |
If |
default |
If |
A vector of length 1 or n, matching the length of the logical input or output vectors. Inconsistent lengths will generate an error.
in_case_fct()
to return a factor and
in_case_list()
to return a list
switch_case()
a simpler alternative for when each case involves
==
or %in%
fn_case()
, a simpler alternative for when each case uses the
same function
if_case()
, a pipeable alternative to dplyr::if_else()
dplyr::case_when()
, from which this function is derived
# Non-piped statements are handled the same as dplyr::case_when() x <- 1:30 in_case( x %% 15 == 0 ~ "fizz buzz", x %% 3 == 0 ~ "fizz", x %% 5 == 0 ~ "buzz", TRUE ~ x ) # A vector can be directly piped into in_case() without error 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", TRUE ~ . ) # in_case() silently converts types 1:30 %>% in_case( . %% 15 == 0 ~ 35, . %% 3 == 0 ~ 5, . %% 5 == 0 ~ 7, TRUE ~ NA ) x <- 1:30 try( dplyr::case_when( x %% 15 == 0 ~ 35, x %% 3 == 0 ~ 5, x %% 5 == 0 ~ 7, TRUE ~ NA ) ) # default and preserve make it easier to handle unmatched values 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", default = "pass" ) 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", preserve = TRUE )
# Non-piped statements are handled the same as dplyr::case_when() x <- 1:30 in_case( x %% 15 == 0 ~ "fizz buzz", x %% 3 == 0 ~ "fizz", x %% 5 == 0 ~ "buzz", TRUE ~ x ) # A vector can be directly piped into in_case() without error 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", TRUE ~ . ) # in_case() silently converts types 1:30 %>% in_case( . %% 15 == 0 ~ 35, . %% 3 == 0 ~ 5, . %% 5 == 0 ~ 7, TRUE ~ NA ) x <- 1:30 try( dplyr::case_when( x %% 15 == 0 ~ 35, x %% 3 == 0 ~ 5, x %% 5 == 0 ~ 7, TRUE ~ NA ) ) # default and preserve make it easier to handle unmatched values 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", default = "pass" ) 1:30 %>% in_case( . %% 15 == 0 ~ "fizz buzz", . %% 3 == 0 ~ "fizz", . %% 5 == 0 ~ "buzz", preserve = TRUE )
These functions are equivalent to in_case()
, switch_case()
,
grep_case()
, fn_case()
, and fn_switch_case()
but return
factors with their levels determined by the order of their
case statements.
in_case_fct(..., preserve = FALSE, default = NA, ordered = FALSE) switch_case_fct(x, ..., preserve = FALSE, default = NA, ordered = FALSE) grep_case_fct(x, ..., preserve = FALSE, default = NA, ordered = FALSE) fn_case_fct(x, fn, ..., preserve = FALSE, default = NA, ordered = FALSE) fn_switch_case_fct(x, fn, ..., preserve = FALSE, default = NA, ordered = FALSE)
in_case_fct(..., preserve = FALSE, default = NA, ordered = FALSE) switch_case_fct(x, ..., preserve = FALSE, default = NA, ordered = FALSE) grep_case_fct(x, ..., preserve = FALSE, default = NA, ordered = FALSE) fn_case_fct(x, fn, ..., preserve = FALSE, default = NA, ordered = FALSE) fn_switch_case_fct(x, fn, ..., preserve = FALSE, default = NA, ordered = FALSE)
... |
<
|
preserve |
If |
default |
If |
ordered |
A logical.
If |
x |
A vector |
fn |
A function to apply to the left-hand side of each formula in Either a quoted or unquoted function name, an anonymous The function should take two inputs, the first being |
A factor vector of length 1 or n, matching the length of the logical
input or output vectors.
Levels are determined by the order of inputs to ...
.
Inconsistent lengths will generate an error.
in_case()
, switch_case()
, grep_case()
, fn_case()
, and
fn_case_fct()
on which these functions are based.
1:10 %>% in_case_fct( . %% 2 == 0 ~ "even", . %% 2 == 1 ~ "odd" ) switch_case_fct( c("a", "b", "c"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" ) switch_case_fct( c("a", "b", "c", "d"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" ) switch_case_fct( c("a", "b", "c", "d"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple", preserve = TRUE ) grep_case_fct( c("caterpillar", "dogwood", "catastrophe", "dogma"), "cat" ~ "feline", "dog" ~ "canine" ) fn_case_fct( c("a", "b", "c"), `%in%`, "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" )
1:10 %>% in_case_fct( . %% 2 == 0 ~ "even", . %% 2 == 1 ~ "odd" ) switch_case_fct( c("a", "b", "c"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" ) switch_case_fct( c("a", "b", "c", "d"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" ) switch_case_fct( c("a", "b", "c", "d"), "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple", preserve = TRUE ) grep_case_fct( c("caterpillar", "dogwood", "catastrophe", "dogma"), "cat" ~ "feline", "dog" ~ "canine" ) fn_case_fct( c("a", "b", "c"), `%in%`, "c" ~ "cantaloupe", "b" ~ "banana", "a" ~ "apple" )
These functions are equivalent to in_case()
, switch_case()
,
grep_case()
, fn_case()
, and fn_switch_case()
but return
lists.
in_case_list(..., preserve = FALSE, default = NA) switch_case_list(x, ..., preserve = FALSE, default = NA) grep_case_list(x, ..., preserve = FALSE, default = NA) fn_case_list(x, fn, ..., preserve = FALSE, default = NA) fn_switch_case_list(x, fn, ..., preserve = FALSE, default = NA)
in_case_list(..., preserve = FALSE, default = NA) switch_case_list(x, ..., preserve = FALSE, default = NA) grep_case_list(x, ..., preserve = FALSE, default = NA) fn_case_list(x, fn, ..., preserve = FALSE, default = NA) fn_switch_case_list(x, fn, ..., preserve = FALSE, default = NA)
... |
<
|
preserve |
If |
default |
If |
x |
A vector |
fn |
A function to apply to the left-hand side of each formula in Either a quoted or unquoted function name, an anonymous The function should take two inputs, the first being |
This can be useful when returning a non-atomic value and/or when you want to create a list column inside a tibble.
A list of length 1 or n, matching the length of the logical input vector.
in_case()
, switch_case()
, grep_case()
, fn_case()
, and
fn_case_fct()
on which these functions are based.
1:3 %>% in_case_list( . < 2 ~ mtcars, default = letters )
1:3 %>% in_case_list( . < 2 ~ mtcars, default = letters )
Switch-style recoding of values
switch_case(x, ..., preserve = FALSE, default = NA) fn_switch_case(x, fn, ..., preserve = FALSE, default = NA)
switch_case(x, ..., preserve = FALSE, default = NA) fn_switch_case(x, fn, ..., preserve = FALSE, default = NA)
x |
A vector |
... |
<
|
preserve |
If |
default |
If |
fn |
A function to apply to the left-hand side of each formula in |
A vector of the same length as x
.
switch_case_fct()
and fn_switch_case_fct()
to return a factor
and switch_case_list()
and fn_switch_case_list()
to return a list
grep_case()
to recode values with string pattern matching
fn_case()
, which applies a function to both x
and each formula's LHS
in_case()
, a pipeable alternative to dplyr::case_when()
switch()
and %in%
, which inspired this function
parties <- sample(c("d", "r", "i", "g", "l"), 20, replace = TRUE) switch_case( parties, "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", c("i", "g", "l") ~ "Other" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", default = "Other" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", preserve = FALSE ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", preserve = TRUE ) data <- c(1, 4, 8, 12, 999, 6, 2, 888, 4, 6, 777) fn_switch_case( data, function(x) paste(rep(x, 3), collapse = ""), 7 ~ "Not asked", 8 ~ "Refused", 9 ~ "Missing", preserve = TRUE )
parties <- sample(c("d", "r", "i", "g", "l"), 20, replace = TRUE) switch_case( parties, "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", "i" ~ "Independent", "g" ~ "Green", "l" ~ "Libertarian" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", c("i", "g", "l") ~ "Other" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", default = "Other" ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", preserve = FALSE ) parties %>% switch_case( "d" ~ "Democrat", "r" ~ "Republican", preserve = TRUE ) data <- c(1, 4, 8, 12, 999, 6, 2, 888, 4, 6, 777) fn_switch_case( data, function(x) paste(rep(x, 3), collapse = ""), 7 ~ "Not asked", 8 ~ "Refused", 9 ~ "Missing", preserve = TRUE )