Skip to content

Commit ef1498e

Browse files
authored
Rework case_when() on top of vctrs::vec_case_when() (#7727)
* Rework `case_when()` on top of `vctrs::vec_case_when()` * NEWS * Bring over a few tests from `vec_case_when()` * Switch from `cases` to `conditions` to match vctrs
1 parent c0aebf0 commit ef1498e

File tree

12 files changed

+104
-1044
lines changed

12 files changed

+104
-1044
lines changed

NEWS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@
2929

3030
The recycling behavior that allows this style of `case_when()` to work is unsafe, and can result in silent bugs that we'd like to guard against with an error in the future (#7082).
3131

32-
* The following vector functions have gotten significantly faster and use much less memory due to a rewrite in C via vctrs (#7723):
32+
* The following vector functions have gotten significantly faster and use much less memory due to a rewrite in C via vctrs (#7723, #7725, #7727):
3333

3434
* `if_else()`
35+
* `case_when()`
3536
* `coalesce()`
3637

3738
* `if_else()` no longer allows `condition` to be a logical array. It must be a logical vector with no `dim` attribute (#7723).

R/case-match.R

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,30 +168,24 @@ vec_case_match <- function(
168168
obj_check_list(haystacks, arg = haystacks_arg, call = call)
169169
list_check_all_vectors(haystacks, arg = haystacks_arg, call = call)
170170

171-
if (length(haystacks) == 0L) {
172-
# `case_match()` is like `case_when()` and doesn't allow empty `...`,
173-
# even though `vec_case_when()` is well defined for this case.
174-
abort("At least one condition must be supplied.", call = call)
175-
}
176-
177171
haystacks <- vec_cast_common(
178172
!!!haystacks,
179173
.to = needles,
180174
.arg = haystacks_arg,
181175
.call = call
182176
)
183177

184-
cases <- map(haystacks, vec_in, needles = needles)
178+
conditions <- map(haystacks, vec_in, needles = needles)
185179

186180
size <- vec_size(needles)
187181

188-
vctrs::vec_case_when(
189-
cases = cases,
182+
vec_case_when(
183+
conditions = conditions,
190184
values = values,
191185
default = default,
192186
ptype = ptype,
193187
size = size,
194-
cases_arg = "",
188+
conditions_arg = "",
195189
values_arg = values_arg,
196190
default_arg = default_arg,
197191
error_call = call

R/case-when.R

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,20 @@ case_when <- function(..., .default = NULL, .ptype = NULL, .size = NULL) {
170170
)
171171

172172
# Only recycle `conditions`. Expect that `vec_case_when()` requires all
173-
# `conditions` to be the same size, but can efficiently recycle `values`
174-
# at the C level without extra allocations.
173+
# `conditions` to be the same size, but can efficiently recycle `values` at
174+
# the C level without extra allocations.
175175
conditions <- vec_recycle_common(!!!conditions, .size = .size)
176176

177177
vec_case_when(
178178
conditions = conditions,
179179
values = values,
180-
conditions_arg = "",
181-
values_arg = "",
182180
default = .default,
183-
default_arg = ".default",
184181
ptype = .ptype,
185182
size = .size,
186-
call = current_env()
183+
conditions_arg = "",
184+
values_arg = "",
185+
default_arg = ".default",
186+
error_call = current_env()
187187
)
188188
}
189189

@@ -335,6 +335,10 @@ case_formula_evaluate <- function(args, default_env, dots_env, error_call) {
335335
n_args <- length(args)
336336
seq_args <- seq_len(n_args)
337337

338+
if (n_args == 0L) {
339+
abort("At least one condition must be supplied.", call = error_call)
340+
}
341+
338342
pairs <- map2(
339343
.x = args,
340344
.y = seq_args,

R/coalesce.R

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ coalesce <- function(..., .ptype = NULL, .size = NULL) {
7373
values <- args$values
7474
default <- args$default
7575

76-
cases <- map(values, function(value) {
76+
conditions <- map(values, function(value) {
7777
!vec_detect_missing(value)
7878
})
7979

80-
vctrs::vec_case_when(
81-
cases = cases,
80+
vec_case_when(
81+
conditions = conditions,
8282
values = values,
8383
default = default,
8484
ptype = .ptype,

R/utils.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ paste_line <- function(...) {
88
paste(chr(...), collapse = "\n")
99
}
1010

11+
vec_paste0 <- function(...) {
12+
args <- vec_recycle_common(...)
13+
exec(paste0, !!!args)
14+
}
15+
1116
# Until vctrs::new_data_frame() forwards row names automatically
1217
dplyr_new_data_frame <- function(
1318
x = data.frame(),

R/vec-case-when.R

Lines changed: 0 additions & 223 deletions
This file was deleted.

tests/testthat/_snaps/case-match.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,6 @@
1414
Error in `case_match()`:
1515
! At least one condition must be supplied.
1616

17-
---
18-
19-
Code
20-
vec_case_match(1, haystacks = list(), values = list())
21-
Condition
22-
Error in `vec_case_match()`:
23-
! At least one condition must be supplied.
24-
2517
# `.default` is part of common type computation
2618

2719
Code

0 commit comments

Comments
 (0)