Skip to content

Commit 478d0c8

Browse files
salim-bhadley
andauthored
Add is_node argument to list_flatten() (#1179)
--------- Co-authored-by: Hadley Wickham <h.wickham@gmail.com>
1 parent f9a5c89 commit 478d0c8

File tree

5 files changed

+50
-3
lines changed

5 files changed

+50
-3
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# purrr (development version)
22

3+
* `list_flatten()` gains an `is_node` parameter taking a predicate function that determines whether an input element is a node or a leaf (@salim-b, #1179).
4+
35
* `in_parallel()` now accepts objects, including helper functions, supplied to `...` for all locally-defined functions (#1208).
46

57
* `in_parallel()` now works in conjunction with string and list values supplied to the `.progress` argument of map functions (#1203).

R/list-flatten.R

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#' `"check_unique"`. See [vctrs::vec_as_names()] for the meaning of these
1212
#' options.
1313
#' @inheritParams rlang::args_dots_empty
14+
#' @inheritParams modify_tree
1415
#' @return A list of the same type as `x`. The list might be shorter
1516
#' if `x` contains empty lists, the same length if it contains lists
1617
#' of length 1 or no sub-lists, or longer if it contains lists of
@@ -40,13 +41,31 @@
4041
#' x |> list_flatten() |> names()
4142
#' x |> list_flatten(name_spec = "{outer}") |> names()
4243
#' x |> list_flatten(name_spec = "{inner}") |> names()
44+
#'
45+
#' # Set `is_node = is.list` to also flatten richer objects built on lists like
46+
#' # data frames and linear models
47+
#' df <- data.frame(x = 1:3, y = 4:6)
48+
#' x <- list(
49+
#' a_string = "something",
50+
#' a_list = list(1:3, "else"),
51+
#' a_df = df
52+
#' )
53+
#' x |> list_flatten(is_node = is.list)
54+
#'
55+
#' # Note that objects that are already "flat" retain their classes
56+
#' list_flatten(df, is_node = is.list)
4357
list_flatten <- function(
4458
x,
4559
...,
60+
is_node = NULL,
4661
name_spec = "{outer}_{inner}",
4762
name_repair = c("minimal", "unique", "check_unique", "universal")
4863
) {
49-
obj_check_list(x)
64+
is_node <- as_is_node(is_node)
65+
if (!is_node(x)) {
66+
cli::cli_abort("{.arg x} must be a node.")
67+
}
68+
5069
check_dots_empty()
5170
check_string(name_spec)
5271

@@ -55,7 +74,7 @@ list_flatten <- function(
5574

5675
# Unclass S3 lists to avoid their coercion methods. Wrap atoms in a
5776
# list of size 1 so the elements can be concatenated in a single list.
58-
proxy <- map_if(proxy, obj_is_list, unclass, .else = list)
77+
proxy <- map_if(proxy, is_node, unclass, .else = list)
5978

6079
out <- list_unchop(
6180
proxy,

man/list_flatten.Rd

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/list-flatten.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
list_flatten(1:2)
55
Condition
66
Error in `list_flatten()`:
7-
! `x` must be a list, not an integer vector.
7+
! `x` must be a node.
88

tests/testthat/test-list-flatten.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,8 @@ test_that("list_flatten() works with vctrs::list_of()", {
7272
list_of(1, 2, 3)
7373
)
7474
})
75+
76+
test_that("list_flatten() honors its is_node param", {
77+
expect_equal(list_flatten(list(mtcars)), list(mtcars))
78+
expect_equal(list_flatten(list(mtcars), is_node = is.list), as.list(mtcars))
79+
})

0 commit comments

Comments
 (0)