Skip to content

Commit

Permalink
Merge pull request #396 from tidyverse/rank-funs
Browse files Browse the repository at this point in the history
Translate `min_rank`, `dense_rank`, `percent_rank`, & `cume_dist`
  • Loading branch information
markfairbanks authored Nov 1, 2022
2 parents b42d698 + e8ca0c9 commit 5d71f4c
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# dtplyr (development version)

* `min_rank()`, `dense_rank()`, `percent_rank()`, & `cume_dist()` are now translated
to their `data.table` equivalents (#396)

* `names_glue` now works in `pivot_wider()` when `names_from` contains `NA`s (#394)

* `full_join()` now produces output with correctly named columns when a non-default
Expand Down
29 changes: 26 additions & 3 deletions R/tidyeval.R
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ dt_squash_call <- function(x, env, data, j = TRUE) {
} else if (is_call(x, "cur_group_rows")) {
quote(.I)
} else if (is_call(x, "desc")) {
if (!has_length(x, 2L)) {
abort("`desc()` expects exactly one argument.")
}
check_one_arg(x)
x[[1]] <- sym("-")
x[[2]] <- dt_squash(x[[2]], env, data, j)
x
Expand Down Expand Up @@ -212,6 +210,24 @@ dt_squash_call <- function(x, env, data, j = TRUE) {
} else if (is_call(x, "row_number", n = 1)) {
arg <- dt_squash(x[[2]], env, data, j = j)
expr(frank(!!arg, ties.method = "first", na.last = "keep"))
} else if (is_call(x, "min_rank")) {
check_one_arg(x)
arg <- dt_squash(x[[2]], env, data, j = j)
expr(frank(!!arg, ties.method = "min", na.last = "keep"))
} else if (is_call(x, "dense_rank")) {
check_one_arg(x)
arg <- dt_squash(x[[2]], env, data, j = j)
expr(frank(!!arg, ties.method = "dense", na.last = "keep"))
} else if (is_call(x, "percent_rank")) {
check_one_arg(x)
arg <- dt_squash(x[[2]], env, data, j = j)
frank_expr <- expr((frank(!!arg, ties.method = "min", na.last = "keep") - 1))
expr(!!frank_expr / (sum(!is.na(!!arg)) - 1))
} else if (is_call(x, "cume_dist")) {
check_one_arg(x)
arg <- dt_squash(x[[2]], env, data, j = j)
frank_expr <- expr(frank(!!arg, ties.method = "max", na.last = "keep"))
expr(!!frank_expr / sum(!is.na(!!arg)))
} else if (is.function(x[[1]]) || is_call(x, "function")) {
simplify_function_call(x, env, data, j = j)
} else if (is_call(x, c("glue", "str_glue")) && j) {
Expand Down Expand Up @@ -301,3 +317,10 @@ fun_name <- function(fun) {

NULL
}

check_one_arg <- function(x) {
fun <- as_name(x[[1]])
if (!has_length(x, 2L)) {
abort(glue("`{fun}()` expects exactly one argument."))
}
}
2 changes: 1 addition & 1 deletion tests/testthat/_snaps/tidyeval.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
Code
capture_dot(df, desc(a, b))
Condition
Error in `dt_squash_call()`:
Error in `check_one_arg()`:
! `desc()` expects exactly one argument.

17 changes: 16 additions & 1 deletion tests/testthat/test-tidyeval.R
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ test_that("n() is equivalent to .N", {
)
})

test_that("row_number() is equivalent .I", {
test_that("row_number() is equivalent seq_len(.N)", {
dt <- lazy_dt(data.frame(g = c(1, 1, 2), x = 1:3))

expect_equal(
Expand All @@ -286,6 +286,21 @@ test_that("row_number(x) is equivalent to rank", {
)
})

test_that("ranking functions are translated", {
df <- lazy_dt(tibble(x = c(1, 2, NA, 1, 0, NaN)))

res <- df %>%
mutate(percent_rank = percent_rank(x),
min_rank = min_rank(x),
dense_rank = dense_rank(x),
cume_dist = cume_dist(x))

expect_equal(pull(res, percent_rank), c(1 / 3, 1, NA, 1 / 3, 0, NA))
expect_equal(pull(res, min_rank), c(2L, 4L, NA, 2L, 1L, NA))
expect_equal(pull(res, dense_rank), c(2L, 3L, NA, 2L, 1L, NA))
expect_equal(pull(res, cume_dist), c(.75, 1, NA, .75, .25, NA))
})

test_that("scoped verbs produce nice output", {
dt <- lazy_dt(data.table(x = 1:5), "DT")

Expand Down

0 comments on commit 5d71f4c

Please sign in to comment.