Reputation: 2143
This fails:
library(tidyverse)
myFn <- function(nmbr){
case_when(
nmbr > 3 ~ letters[1:3],
TRUE ~ letters[1:2]
)
}
myFn(4)
# Error: `TRUE ~ letters[1:2]` must be length 3 or one, not 2
# Run `rlang::last_error()` to see where the error occurred.
Why does it fail? Why is case_when
built in such a way that its branches can't return different-length vectors? I'd like myFn
to work so that I can do things like:
tibble(fruit = c("apple", "grape"),
count = 3:4) %>%
mutate(bowl = myFn(count)) %>%
unnest(col = "bowl")
and get
# A tibble: 5 x 3
fruit count bowl
<chr> <int> <int>
1 apple 3 a
2 apple 3 b
3 grape 4 a
4 grape 4 b
5 grape 4 c
I can get it to work - by writing a non-vectorized myFn
using if/else
, then wrapping it in map
, but why should I have to?
Upvotes: 5
Views: 1392
Reputation: 194
Extending r2Evans answer, you can unlist prior to returning. Here is my code that I am using as part of my nesting algorithm.
test_fn <- function(StockCode) {
L <- dplyr::case_when(stringr::str_starts(StockCode, "A") ~ list(7500),
stringr::str_starts(StockCode, "FL") ~ list(6000),
stringr::str_starts(StockCode, "PIPE") ~ list(6500),
stringr::str_starts(StockCode, "RHS") ~
list(c(8000, 12000)),
stringr::str_starts(StockCode, "RND") ~ list(6000),
stringr::str_starts(StockCode, "SQ") ~ list(6000),
TRUE ~
list(c(9000, 10500, 12000, 13500, 15000, 16500, 18000))) %>%
unlist()
return(L)
}
test_fn("RHS")
test_fn("CH")
The output will be the vector assigned to the list.
Upvotes: 0
Reputation: 160437
Per my comments, your function needs to return one element for each row of input. However, each of those elements can be a list
of length 0 or more (and arbitrary complexity). Try this:
myFn <- function(nmbr){
case_when(
nmbr > 3 ~ list(letters[1:3]),
TRUE ~ list(letters[1:2])
)
}
tibble(fruit = c("apple", "grape"),
count = 3:4) %>%
mutate(bowl = myFn(count))
# # A tibble: 2 x 3
# fruit count bowl
# <chr> <int> <list>
# 1 apple 3 <chr [2]>
# 2 grape 4 <chr [3]>
tibble(fruit = c("apple", "grape"),
count = 3:4) %>%
mutate(bowl = myFn(count)) %>%
unnest(col = "bowl")
# # A tibble: 5 x 3
# fruit count bowl
# <chr> <int> <chr>
# 1 apple 3 a
# 2 apple 3 b
# 3 grape 4 a
# 4 grape 4 b
# 5 grape 4 c
Upvotes: 5