Skip to content
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

Preserve classes in pmap() #554

Merged
merged 1 commit into from
Nov 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# purrr 0.2.4.9000

* `pmap()` and `pwalk()` now preserve class for inputs of `factor`, `Date`, `POSIXct`
and other atomic S3 classes with an appropriate `[[` method (#358, @mikmart).

* `compose()` now supports composition with lambdas (@ColinFay, #556)

* Fixed a `pmap()` crash with empty lists on the Win32 platform (#565).
Expand Down
5 changes: 1 addition & 4 deletions R/map.R
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,6 @@ map_dfc <- function(.x, .f, ...) {
#' @export
#' @rdname map
walk <- function(.x, .f, ...) {
.f <- as_mapper(.f, ...)
for (i in seq_along(.x)) {
.f(.x[[i]], ...)
}
map(.x, .f, ...)
invisible(.x)
}
8 changes: 2 additions & 6 deletions R/map2-pmap.R
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ map2_df <- map2_dfr
#' @export
#' @rdname map2
walk2 <- function(.x, .y, .f, ...) {
pwalk(list(.x, .y), .f, ...)
map2(.x, .y, .f, ...)
invisible(.x)
}

Expand Down Expand Up @@ -245,10 +245,6 @@ pmap_df <- pmap_dfr
#' @export
#' @rdname map2
pwalk <- function(.l, .f, ...) {
.f <- as_mapper(.f, ...)
args_list <- transpose(recycle_args(.l))
for (args in args_list) {
do.call(".f", c(args, list(...)))
}
pmap(.l, .f, ...)
invisible(.l)
}
12 changes: 8 additions & 4 deletions src/map.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ SEXP pmap_impl(SEXP env, SEXP l_name_, SEXP f_name_, SEXP type_) {
SEXP i = Rf_install("i");
SEXP one = PROTECT(Rf_ScalarInteger(1));

// Construct call like f(.x[[c(1, i)]], .x[[c(2, i)]], ...)
// Construct call like f(.l[[1]][[i]], .l[[2]][[i]], ...)
//
// Currently accessing S3 vectors in a list like .l[[c(1, i)]] will not
// preserve the class (cf. #358).
//
// We construct the call backwards because can only add to the front of a
// linked list. That makes PROTECTion tricky because we need to update it
// each time to point to the start of the linked list.
Expand All @@ -186,10 +190,10 @@ SEXP pmap_impl(SEXP env, SEXP l_name_, SEXP f_name_, SEXP type_) {
for (int j = m - 1; j >= 0; --j) {
int nj = Rf_length(VECTOR_ELT(l_val, j));

// Construct call like .l[[c(j, i)]]
// Construct call like .l[[j]][[i]]
SEXP j_ = PROTECT(Rf_ScalarInteger(j + 1));
SEXP ji_ = PROTECT(Rf_lang3(Rf_install("c"), j_, nj == 1 ? one : i));
SEXP l_ji = PROTECT(Rf_lang3(R_Bracket2Symbol, l, ji_));
SEXP l_j = PROTECT(Rf_lang3(R_Bracket2Symbol, l, j_));
SEXP l_ji = PROTECT(Rf_lang3(R_Bracket2Symbol, l_j, nj == 1 ? one : i));

REPROTECT(f_call = Rf_lcons(l_ji, f_call), fi);
if (has_names && CHAR(STRING_ELT(l_names, j))[0] != '\0')
Expand Down
6 changes: 6 additions & 0 deletions tests/testthat/test-map_n.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,9 @@ test_that("pmap on data frames performs rowwise operations", {
test_that("pmap works with empty lists", {
expect_identical(pmap(list(), identity), list())
})

test_that("preserves S3 class of input vectors (#358)", {
date <- as.Date("2018-09-27")
expect_equal(pmap(list(date), identity), list(date))
expect_output(pwalk(list(date), print), format(date))
})