Home > Software design >  Using case_when with vector outputs of different length - can I avoid this doubling behaviour?
Using case_when with vector outputs of different length - can I avoid this doubling behaviour?

Time:07-08

When I use case_when as below, I end up with an unwanted doubling of outputs that were intended to be of length 1 - presumably because case_when matches the length of all possible output vectors.

a <- 1
b <- 2
decision <- case_when(
  a == b ~ c("A", "B"),
  a > b ~ "A",
  TRUE ~ "B")

result <- decision %>% str_c(" ") %>% paste(collapse = " ")

The result in this scenario is "B B ", when I just want "B ".

When a=b, I get "A B ", which is what I want in that scenario.

Is there any way to stop this behaviour, or an alternative function?

Please note that the above is just the simplest parallel I could write. I am using case_when as part of a custom function to define rules applied to numerous input variables to generate a result call. I had been using multiple if_else statements chained together, but that has significant readability/editing issues and I had been excited to discover case_when and use it instead.

CodePudding user response:

case_when/ifelse/if_else all requires arguments to have equal length. Here, the value returned in some cases have length 2 and some have length 1. It wouldn't work as mentioned in the ?case_when

Both LHS and RHS may have the same length of either 1 or n. The value of n must be consistent across all cases. The case of n == 0 is treated as a variant of n != 1.

Use if/else

decision <- if(a == b) c('A', 'B') else if(a > b) 'A' else 'B'

-testing

library(stringr)
decision %>% 
  str_c(" ") %>% 
  str_c(collapse = " ")
[1] "B "

If we want to still use case_when, wrap it with list so that it returns a length of 1 for all cases and then extract the list element with [[

case_when(
  a == b ~ list(c("A", "B")),
  a > b ~ list("A"),
  TRUE ~ list("B"))[[1]]
[1] "B"

CodePudding user response:

If you want to use case_when you could also use some regex:

a <- 1
b <- 2

decision <- case_when(
  a == b ~ "A B",
  a > b ~ "A",
  TRUE ~ "B")

stringr::str_replace_all(decision, "([A-B])", "\\1\\ ")
  • Related