-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
case_when
returns length-0 option if any option is length-0
#7082
Comments
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as resolved.
This comment was marked as resolved.
First off, just know that I do agree with you here. My ideal version of
And in fact the lower level internal In For some reason we also recycle the LHSs and RHSs together to compute the common size, rather than only using the LHSs (that goes against bullet 2 and causes the issue you are reporting). I can't think of any reason this is useful. It's possible we could look into getting rid of this 2nd behavior, and make
The change would be around here Lines 168 to 170 in 1d17672
|
Also, in |
This also seems to only really affect things when the LHSs all have length 1, causing them to get recycled to any other size (i.e. the size 0 from x <- 1
y <- 1:2
dplyr::case_when(
x == 5 ~ "hello",
x > 10 ~ character(),
.default = "other"
)
#> character(0)
dplyr::case_when(
y == 5 ~ "hello",
y > 10 ~ character(),
.default = "other"
)
#> Error in `dplyr::case_when()`:
#> ! Can't recycle `..1 (left)` (size 2) to match `..2 (right)` (size 0).
#> Backtrace:
#> ▆
#> 1. ├─dplyr::case_when(y == 5 ~ "hello", y > 10 ~ character(), .default = "other")
#> 2. │ └─vctrs::vec_size_common(!!!conditions, !!!values, .size = .size)
#> 3. └─vctrs::stop_incompatible_size(...)
#> 4. └─vctrs:::stop_incompatible(...)
#> 5. └─vctrs:::stop_vctrs(...)
#> 6. └─rlang::abort(message, class = c(class, "vctrs_error"), ..., call = call) Created on 2024-09-06 with reprex v2.0.2 |
@DavisVaughan - yep, those two rules match my mental model pretty precisely. I suspect this realistically only happens by accident. I certainly only found out about this behaviour by having something that wound up being length-0 on one of the RHS (pulling text on a filter where a third party had silently stopped providing anything that matched the filter at all). Obviously not the most defensive programming on my part. I can see having to hand the legacy |
See also #7088 where RHS recycling could possibly be used in some cases to incorrectly mimic a simple if statement. I'd argue this should be an error, and changing the behavior as suggested above where the RHSs need to be size 1 or size dplyr::case_when(
FALSE ~ c(1, 2),
TRUE ~ 3
)
#> [1] 3 3 |
I have had similar issues to those discussed here. What surprises me as a user is that the case_when statement doesn't bypass an element that is false instead of checking whether the right side is an acceptable length. example: a <- NULL
b <- case_when(is.character(a) ~ a, TRUE ~ NA)
Error in `dplyr::case_when()`:
! `..1 (right)` must be a vector, not `NULL`.
Hide Traceback
▆
1. ├─dplyr::case_when(is.character(a) ~ a, TRUE ~ NA)
2. │ └─dplyr:::vec_case_when(...)
3. │ └─vctrs::list_check_all_vectors(values, arg = values_arg, call = call)
4. └─vctrs:::stop_scalar_type(`<fn>`(NULL), "..1 (right)", `<env>`)
5. └─vctrs:::stop_vctrs(...)
6. └─rlang::abort(message, class = c(class, "vctrs_error"), ..., call = call) I would expect case_when not to care what the right side of the first argument is given that the left side is false. In this use case I have gone back to an if/else workflow but it's a little less readable and not my usual when working with tidy data. |
@benhmin if you are using |
Thank you, this makes sense. I think one of the main uses cases I have for case_when() is in a piped data manipulation workflow where there are more than two outcomes and so ifelse()/if_else() can't capture them all. I think that would be ok still based on this, yes? |
Like, the outcome possibilities are FWIW
|
case_when
always returns length-0 option if any option is length-0I would expect an error as in
case_match
. This seems to only be an issue if the input tocase_when
is length 1 - it errors otherwise.Created on 2024-09-05 with reprex v2.1.1
The text was updated successfully, but these errors were encountered: