Skip to content

Commit

Permalink
Use .else in atomic modification
Browse files Browse the repository at this point in the history
Fixes #701. Originally implemented by @mgrlich in #724.
  • Loading branch information
hadley committed Sep 6, 2022
1 parent e16c5d4 commit aff6dc5
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 14 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@

## Features and fixes

* `modify_if(.else)` is now actually evaluated for atomic vectors (@mgirlich,
#701).

* `as_mapper()` is now around twice as fast when used with character,
integer, or list (#820).

Expand Down
32 changes: 18 additions & 14 deletions R/modify.R
Original file line number Diff line number Diff line change
Expand Up @@ -212,30 +212,34 @@ modify.pairlist <- function(.x, .f, ...) {
}

#' @export
modify_if.integer <- function(.x, .p, .f, ...) {
sel <- probe(.x, .p)
.x[sel] <- map_int(.x[sel], .f, ...)
.x
modify_if.integer <- function(.x, .p, .f, ..., .else = NULL) {
modify_if_atomic(map_int, .x, .p, .true = .f, .false = .else, ...)
}
#' @export
modify_if.double <- function(.x, .p, .f, ...) {
sel <- probe(.x, .p)
.x[sel] <- map_dbl(.x[sel], .f, ...)
.x
modify_if.double <- function(.x, .p, .f, ..., .else = NULL) {
modify_if_atomic(map_dbl, .x, .p, .true = .f, .false = .else, ...)
}
#' @export
modify_if.character <- function(.x, .p, .f, ...) {
sel <- probe(.x, .p)
.x[sel] <- map_chr(.x[sel], .f, ...)
.x
modify_if.character <- function(.x, .p, .f, ..., .else = NULL) {
modify_if_atomic(map_chr, .x, .p, .true = .f, .false = .else, ...)
}
#' @export
modify_if.logical <- function(.x, .p, .f, ...) {
modify_if.logical <- function(.x, .p, .f, ..., .else = NULL) {
modify_if_atomic(map_lgl, .x, .p, .true = .f, .false = .else, ...)
}

modify_if_atomic <- function(.fmap, .x, .p, .true, .false = NULL, ...) {
sel <- probe(.x, .p)
.x[sel] <- map_lgl(.x[sel], .f, ...)
.x[sel] <- .fmap(.x[sel], .true, ...)

if (!is.null(.false)) {
.x[!sel] <- .fmap(.x[!sel], .false, ...)
}

.x
}


#' @export
modify_at.integer <- function(.x, .at, .f, ...) {
where <- at_selection(names(.x), .at)
Expand Down
5 changes: 5 additions & 0 deletions tests/testthat/test-modify.R
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ test_that("`.else` modifies false elements", {
exp <- modify_if(iris, negate(is.factor), as.integer)
exp <- modify_if(exp, is.factor, as.character)
expect_identical(modify_if(iris, is.factor, as.character, .else = as.integer), exp)

expect_equal(modify_if(c(TRUE, FALSE), ~ .x, ~ FALSE, .else = ~ TRUE), c(FALSE, TRUE))
expect_equal(modify_if(1:2, ~ .x == 1, ~ 3L, .else = ~ 4L), c(3, 4))
expect_equal(modify_if(c(1, 10), ~ .x < 5, ~ .x * 10, .else = ~ .x / 2), c(10, 5))
expect_equal(modify_if(c("a", "b"), ~ .x == "a", ~ "A", .else = ~ "B"), c("A", "B"))
})

test_that("modify family preserves NULLs", {
Expand Down

0 comments on commit aff6dc5

Please sign in to comment.