purrr 1.0.0
Breaking changes
Core purpose refinements
-
cross()
and all its variants have been deprecated in favour of
tidyr::expand_grid()
. These functions were slow and buggy and we
no longer think they are the right approach to solving this problem.
See #768 for more information. -
update_list()
(#858) andrerun()
(#877), and the use of tidyselect
withmap_at()
and friends (#874) have been deprecated. These functions
use some form of non-standard evaluation which we now believe is a poor
fit for purrr. -
The
lift_*
family of functions has been deprecated. We no longer believe
these to be a good fit for purrr because they rely on a style of function
manipulation that is very uncommon in R code (#871). -
prepend()
,rdunif()
,rbernoulli()
,when()
, andlist_along()
have
all been deprecated (#925). It's now clear that they don't align with the
core purpose of purrr. -
splice()
is deprecated because we no longer believe that automatic
splicing makes for good UI. Instead uselist2()
+!!!
or
list_flatten()
(#869).
Mapping
-
Use of map functions with expressions, calls, and pairlists has been
deprecated (#961). -
All map
_raw()
variants have been deprecated because they are of limited
use and you can now usemap_vec()
instead (#903). -
In
map_chr()
, automatic conversion from logical, integer, and double to
character is now deprecated. Use an explicitas.character()
if needed
(#904).
Deprecation next steps
-
as_function()
and the...f
argument topartial()
are no longer
supported. They have been defunct for quite some time. -
Soft deprecated functions:
%@%
,reduce_right()
,reduce2_right()
,
accumulate_right()
are now fully deprecated. Similarly, the
.lazy
,.env
, and.first
arguments topartial()
,
and the.right
argument todetect()
anddetect_index()
are fully deprecated. Removing elements withNULL
inlist_modify()
and
list_merge()
is now fully deprecated. -
is_numeric()
andis_scalar_numeric()
have been removed. They have
been deprecated since purrr 0.2.3 (Sep 2017). -
invoke_*()
is now deprecated. It was superseded in 0.3.0 (Jan 2019) and
3.5 years later, we have decided to deprecate it as part of the API
refinement in the 1.0.0 release. -
map_call()
has been removed. It was made defunct in 0.3.0 (Jan 2019).
New features
-
*_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()
, andpmap_vec()
work on all types of vectors,
extendingmap_lgl()
,map_int()
, and friends so that you can easily work
with dates, factors, date-times and more (#435). -
New
keep_at()
anddiscard_at()
that work likekeep()
anddiscard()
but operation on element names rather than element contents (#817). -
Some mapping functions have now a
.progress
argument to create a
progress bar. See?progress_bars
(#149). -
purrr is now licensed as MIT (#805).
-
modify()
,modify_if()
,modify_at()
, andmodify2()
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
to a regular section with a note that they might not work (#936). -
When map functions fail, they now report the element they failed at (#945).
-
New
modify_tree()
for recursively modifying nested data structures (#720).
Flattening and simplification
-
New
list_c()
,list_rbind()
, andlist_cbind()
make it easy to
c()
,rbind()
, orcbind()
all of the elements in a list. -
New
list_simplify()
reduces a list of length-1 vectors to a simpler atomic
or S3 vector (#900). -
New
list_transpose()
which automatically simplifies if possible (#875). -
accumulate()
andaccumulate2()
now both simplify the output if possible
using vctrs. New argumentssimplify
andptype
allow you to control the
details of simplification (#774, #809). -
flatten()
and friends are superseded in favour oflist_flatten()
,
list_c()
,list_cbind()
, andlist_rbind()
. -
*_dfc()
and*_dfr()
have been superseded in favour of using the
appropriate map function along withlist_rbind()
orlist_cbind()
(#912). -
simplify()
,simplify_all()
, andas_vector()
have been superseded in
favour oflist_simplify()
. It provides a more consistent definition of
simplification (#900). -
transpose()
has been superseded in favour oflist_transpose()
(#875).
It has built-in simplification.
Tidyverse consistency
-
_lgl()
,_int()
,_int()
, and_dbl()
now use the same (strict) coercion
methods as vctrs (#904). This means that:-
map_chr(TRUE, identity)
,map_chr(0L, identity)
, and
map_chr(1L, identity)
are deprecated because we now believe that
converting a logical/integer/double to a character vector should require
an explicit coercion. -
map_int(1.5, identity)
now fails because we believe that silently
truncating doubles to integers is dangerous. But note that
map_int(1, identity)
still works since no numeric precision is lost. -
map_int(c(TRUE, FALSE), identity)
,map_dbl(c(TRUE, FALSE), identity)
,
map_lgl(c(1L, 0L), identity)
andmap_lgl(c(1, 0), identity)
now
succeed because 1/TRUE and 0/FALSE should be interchangeable.
-
-
map2()
,modify2()
, andpmap()
now use tidyverse recycling rules where
vectors of length 1 are recycled to any size but all others must have
the same length (#878). -
map2()
andpmap()
now recycle names of their first input if
needed (#783). -
modify()
,modify_if()
, andmodify_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 nowpluck_depth()
and works with more types of input
(#818). -
pluck()
now requires indices to be length 1 (#813). It also now reports
the correct type if you supply an unexpected index. -
pluck()
now accepts negative integers, indexing from the right (#603). -
pluck()
andchuck()
now fail if you provide named inputs to ... (#788). -
pluck()
no longer replaces 0-length vectors withdefault
; it now
only applies absent andNULL
components (#480). -
pluck<-
/assign_in()
can now modify non-existing locations (#704).
Setting with NULL
-
pluck<-
/assign_in()
now sets elements toNULL
rather than removing them
(#636). Now use the explicitzap()
if you want to remove elements. -
modify()
,modify2()
, andmodify_if()
now correctly handleNULL
s
in replacement values (#655, #746, #753). -
list_modify()
's interface has been standardised. Modifying withNULL
now always creates aNULL
in the output (#810)
list_
functions`
-
New
list_assign()
which is similar tolist_modify()
but doesn't work
recursively (#822). -
list_modify()
no longer recurses into data frames (and other objects built
on top of lists that are fundamentally non-list like) (#810). You can
revert to the previous behaviour by setting.is_node = is.list
.
Minor improvements and bug fixes
-
capture_output()
correctly usesconditionMessage()
instead of directly
interrogating themessage
field (#1010). -
modify()
no longer works with calls or pairlists. -
modify_depth()
is no longer a generic. This makes it more consistent
withmap_depth()
. -
map_depth()
andmodify_depth()
have a newis_node
argument that
allows you to control what counts as a level. The default uses
vec_is_list()
to avoid recursing into rich S3 objects like linear models
or data.frames (#958, #920). -
map_depth()
andmodify_depth()
now correctly recurse at depth 1. -
as_mapper()
is now around twice as fast when used with character,
integer, or list (#820). -
possibly()
now defaultsotherwise
to NULL. -
modify_if(.else)
is now actually evaluated for atomic vectors (@mgirlich,
#701). -
lmap_if()
correctly handles.else
functions (#847). -
every()
now correctly propagates missing values using the same
rules as&&
(#751). Internally, it has become a wrapper around
&&
. This makes it consistent with&&
and also withsome()
which has always been a wrapper around||
with the same
propagation rules. -
every()
andsome()
now properly check the return value of their
predicate function. It must now return aTRUE
,FALSE
, orNA
. -
Greatly improved performance of functions created with
partial()
(#715).
Their invocation is now as fast as for functions creating manually. -
partial()
no longer inlines the function in the call stack. This
fixes issues whenpartial()
is used withlm()
for instance (#707).