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

Apply vctrs principles to map() and modify() #894

Merged
merged 27 commits into from
Sep 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9a82a56
Implement map_vec()
hadley Aug 27, 2022
194828f
Implementation feedback
hadley Aug 29, 2022
a717b6c
Merged origin/main into map-vec
hadley Aug 29, 2022
7733dc1
Add tests to clarify behaviour
hadley Aug 29, 2022
bdde69f
Merge commit '3b5add2db99a35ec1392ad23dc021b7ccadbbbbb'
hadley Sep 14, 2022
63119fd
Use new simplify tooling
hadley Sep 14, 2022
0aff22d
Remove unneeded import
hadley Sep 14, 2022
b852864
Merged origin/main into map-vec
hadley Sep 15, 2022
5671d9d
Update snapshot
hadley Sep 15, 2022
4d5b102
Update modify and modify_at
hadley Sep 15, 2022
ed04346
Add map2_vec() and pmap_vec()
hadley Sep 15, 2022
e093621
Move map_chr to correct position
hadley Sep 15, 2022
5167acc
Update modify2
hadley Sep 15, 2022
08fe6e6
And modify_if
hadley Sep 15, 2022
b2c09b3
Add news bullets
hadley Sep 15, 2022
903bdd3
Minimise map_vec() tests given implementation
hadley Sep 15, 2022
e203d7e
Update map2 tests
hadley Sep 15, 2022
3da5be6
Update pmap tests
hadley Sep 15, 2022
8f82675
At test for non-vector lists
hadley Sep 15, 2022
4983571
Test fallbacks
hadley Sep 15, 2022
961eeea
Tweak modify's handling of data frames
hadley Sep 16, 2022
2e7af8c
modify functions are no longer generics
hadley Sep 16, 2022
0b7ce2e
Polish modify tests
hadley Sep 16, 2022
ecae803
Tweak error message
hadley Sep 16, 2022
524e484
Add test for ptype
hadley Sep 16, 2022
9d45521
Tweak return type description some more
hadley Sep 16, 2022
87cd328
Merge commit '426acdd50424b8cd6029d237c4d4e81d94ec42a6'
hadley Sep 16, 2022
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
24 changes: 3 additions & 21 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,6 @@ S3method(as_mapper,character)
S3method(as_mapper,default)
S3method(as_mapper,list)
S3method(as_mapper,numeric)
S3method(modify,character)
S3method(modify,default)
S3method(modify,double)
S3method(modify,integer)
S3method(modify,logical)
S3method(modify,pairlist)
S3method(modify2,character)
S3method(modify2,default)
S3method(modify2,double)
S3method(modify2,integer)
S3method(modify2,logical)
S3method(modify_at,character)
S3method(modify_at,default)
S3method(modify_at,double)
S3method(modify_at,integer)
S3method(modify_at,logical)
S3method(modify_if,character)
S3method(modify_if,default)
S3method(modify_if,double)
S3method(modify_if,integer)
S3method(modify_if,logical)
S3method(print,purrr_function_compose)
S3method(print,purrr_function_partial)
S3method(print,purrr_rate_backoff)
Expand Down Expand Up @@ -152,6 +131,7 @@ export(map2_dfr)
export(map2_int)
export(map2_lgl)
export(map2_raw)
export(map2_vec)
export(map_at)
export(map_chr)
export(map_dbl)
Expand All @@ -163,6 +143,7 @@ export(map_if)
export(map_int)
export(map_lgl)
export(map_raw)
export(map_vec)
export(modify)
export(modify2)
export(modify_at)
Expand All @@ -184,6 +165,7 @@ export(pmap_dfr)
export(pmap_int)
export(pmap_lgl)
export(pmap_raw)
export(pmap_vec)
export(possibly)
export(prepend)
export(pwalk)
Expand Down
15 changes: 15 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
* `*_at()` can now take a function (or formula) that's passed the vector of
element names and returns the elements to select.

* New `map_vec()`, `map2_vec()`, and `pmap_vec()` work on all types of vectors,
extending `map_lgl()`, `map_int()`, and friends so that you can easily work
with dates, factors, date-times and more (#435).

* New `keep_at()` and `discard_at()` that work like `keep()` and `discard()`
but operation on element names rather than element contents (#817).

Expand All @@ -78,6 +82,11 @@

* purrr is now licensed as MIT (#805).

* `modify()`, `modify_if()`, `modify_at()`, and `modify2()` are no longer
generics. We have discovered a simple implementation that no longer requires
genericity and methods were only provided by a very small number of packages
(#894).

* purrr now uses the base pipe (`|>`) and anonymous function short hand (`\(x)`),
in all examples. This means that examples will no longer work in R 4.0 and
earlier so in those versions of R, the examples are automatically converted
Expand Down Expand Up @@ -122,6 +131,10 @@
* `map2()` and `pmap()` now recycle names of their first input if
needed (#783).

* `modify()`, `modify_if()`, and `modify_at()` have been reimplemented using
vctrs principles. This shouldn't have an user facing impact, but it does
make the implementation much simpler.

### Plucking

* `vec_depth()` is now `pluck_depth()` and works with more types of input
Expand Down Expand Up @@ -160,6 +173,8 @@

## Minor improvements and bug fixes

* `modify()` no longer supports modifying calls or pairlists.

* `modify_depth()` is no longer a generic. This makes it more consistent
with `map_depth()`.

Expand Down
38 changes: 28 additions & 10 deletions R/map.R
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#' atomic vector of the indicated type (or die trying). For these functions,
#' `.f` must return a length-1 vector of the appropriate type.
#'
#' * `map_vec()` simplifies to the common type of the output. It works with
#' most types of simple vectors like Date, POSIXct, factors, etc.
#'
#' * `walk()` calls `.f` for its side-effect and returns
#' the input `.x`.
#'
Expand All @@ -36,15 +39,20 @@
#' for details.
#' @returns
#' The output length is determined by the length of the input.
#' The output names are determined by the input names.
#' The output type is determined by the suffix:
#'
#' * No suffix: a list.
#' * No suffix: a list; `.f()` can return anything.
#'
#' * `_lgl()`, `_int()`, `_dbl()`, `_chr()` return a logical, integer, double,
#' or character vector respectively; `.f()` must return a compatible atomic
#' vector of length 1.
#'
#' * `_lgl`, `_int`, `_dbl`, `_chr` return a logical, integer, double,
#' or character vector respectively. It will be named if the input was named.
#' * `_vec()` return an atomic or S3 vector, the same type that `.f` returns.
#' `.f` can return pretty much any type of vector, as long as its length 1.
#'
#' * `walk()` returns the input `.x` (invisibly). This makes it easy to
#' use in a pipe.
#' use in a pipe. The return value of `.f()` is ignored.
#' @export
#' @family map variants
#' @seealso [map_if()] for applying a function to only those elements
Expand Down Expand Up @@ -116,23 +124,33 @@ map_lgl <- function(.x, .f, ..., .progress = FALSE) {

#' @rdname map
#' @export
map_chr <- function(.x, .f, ..., .progress = FALSE) {
map_int <- function(.x, .f, ..., .progress = FALSE) {
.f <- as_mapper(.f, ...)
.Call(map_impl, environment(), ".x", ".f", "character", .progress)
.Call(map_impl, environment(), ".x", ".f", "integer", .progress)
}

#' @rdname map
#' @export
map_int <- function(.x, .f, ..., .progress = FALSE) {
map_dbl <- function(.x, .f, ..., .progress = FALSE) {
.f <- as_mapper(.f, ...)
.Call(map_impl, environment(), ".x", ".f", "integer", .progress)
.Call(map_impl, environment(), ".x", ".f", "double", .progress)
}

#' @rdname map
#' @export
map_dbl <- function(.x, .f, ..., .progress = FALSE) {
map_chr <- function(.x, .f, ..., .progress = FALSE) {
.f <- as_mapper(.f, ...)
.Call(map_impl, environment(), ".x", ".f", "double", .progress)
.Call(map_impl, environment(), ".x", ".f", "character", .progress)
}

#' @rdname map
#' @param .ptype If `NULL`, the default, the output type is the common type
#' of the elements of the result. Otherwise, supply a "prototype" giving
#' the desired type of output.
#' @export
map_vec <- function(.x, .f, ..., .ptype = NULL, .progress = FALSE) {
out <- map(.x, .f, ..., .progress = .progress)
simplify_impl(out, ptype = .ptype)
}

#' @rdname map
Expand Down
7 changes: 6 additions & 1 deletion R/map2.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,16 @@ map2_chr <- function(.x, .y, .f, ..., .progress = NULL) {
.Call(map2_impl, environment(), ".x", ".y", ".f", "character", .progress)
}

#' @rdname map2
#' @export
map2_vec <- function(.x, .y, .f, ..., .ptype = NULL, .progress = NULL) {
hadley marked this conversation as resolved.
Show resolved Hide resolved
out <- map2(.x, .y, .f, ..., .progress = .progress)
simplify_impl(out, ptype = .ptype)
}

#' @export
#' @rdname map2
walk2 <- function(.x, .y, .f, ...) {
map2(.x, .y, .f, ...)
invisible(.x)
}

Loading