-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy pathlist-simplify.R
More file actions
108 lines (99 loc) · 2.79 KB
/
list-simplify.R
File metadata and controls
108 lines (99 loc) · 2.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#' Simplify a list to an atomic or S3 vector
#'
#' Simplification maintains a one-to-one correspondence between the input
#' and output, implying that each element of `x` must contain a one element
#' vector or a one-row data frame. If you don't want to maintain this
#' correspondence, then you probably want either [list_c()]/[list_rbind()] or
#' [list_flatten()].
#'
#' @param x A list.
#' @param strict What should happen if simplification fails? If `TRUE`
#' (the default) it will error. If `FALSE` and `ptype` is not supplied,
#' it will return `x` unchanged.
#' @param ptype An optional prototype to ensure that the output type is always
#' the same.
#' @inheritParams rlang::args_dots_empty
#' @returns A vector the same length as `x`.
#' @export
#' @examples
#' list_simplify(list(1, 2, 3))
#'
#' # Only works when vectors are length one and have compatible types:
#' try(list_simplify(list(1, 2, 1:3)))
#' try(list_simplify(list(1, 2, "x")))
#'
#' # Unless you strict = FALSE, in which case you get the input back:
#' list_simplify(list(1, 2, 1:3), strict = FALSE)
#' list_simplify(list(1, 2, "x"), strict = FALSE)
list_simplify <- function(x, ..., strict = TRUE, ptype = NULL) {
check_dots_empty()
check_bool(strict)
simplify_impl(x, strict = strict, ptype = ptype)
}
# Wrapper used by purrr functions that do automatic simplification
list_simplify_internal <- function(
x,
simplify = NA,
ptype = NULL,
error_arg = caller_arg(x),
error_call = caller_env()
) {
check_bool(simplify, allow_na = TRUE, call = error_call)
if (!is.null(ptype) && isFALSE(simplify)) {
cli::cli_abort(
"Can't specify {.arg ptype} when `simplify = FALSE`.",
arg = "ptype",
call = error_call
)
}
if (isFALSE(simplify)) {
return(x)
}
simplify_impl(
x,
strict = !is.na(simplify),
ptype = ptype,
error_arg = error_arg,
error_call = error_call
)
}
simplify_impl <- function(
x,
strict = TRUE,
ptype = NULL,
error_arg = caller_arg(x),
error_call = caller_env()
) {
obj_check_list(x, arg = error_arg, call = error_call)
# Handle the cases where we definitely can't simplify
if (strict) {
list_check_all_vectors(x, arg = error_arg, call = error_call)
list_check_all_size(x, 1, arg = error_arg, call = error_call)
} else {
can_simplify <- list_all_vectors(x) && all(list_sizes(x) == 1L)
if (!can_simplify) {
return(x)
}
}
names <- vec_names(x)
x <- vec_set_names(x, NULL)
out <- tryCatch(
list_unchop(
x,
ptype = ptype,
error_arg = error_arg,
error_call = error_call
),
vctrs_error_incompatible_type = function(err) {
if (strict || !is.null(ptype)) {
cnd_signal(err)
} else {
x
}
}
)
if (!is.null(out)) {
out <- vec_set_names(out, names)
}
out
}