-
Notifications
You must be signed in to change notification settings - Fork 275
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
Is flattening c + splicing? #575
Comments
I think the difference between map(x, f, .type = int())
simplify(map(x, f), .type = int()) (Though when the |
What function do you use to turn |
That is |
Oh so what's the equivalent of |
Under simple scenarios, that appears to be x <- list(1, list(2), 3, list(4)) If you pass tmp <- list(list(1), list(2), list(3), list(4))
out <- list(1, 2, 3, 4) If you pass tmp <- list(1L, 2L, 3L, 4L)
out <- int(1L, 2L, 3L, 4L) However I'm not sure that's the correct behaviour. For instance, what should I'm not sure how to translate this in |
So maybe And then I'm not sure we need a function here where the input and output have equal length? (That seems antithetical to flattening/simplifying) |
That makes sense. And then And if map_int(x, f)
int(map(x, f))
x %>% map(f) %>% int() I.e. the length constraint is done by |
(or maybe the rule is that we keep typed variants when they have a computational advantage) |
Yeah, that sounds good. Are we sure we have the names around the right way? Because |
I think Actually one argument against using |
From Michel on Slack: # list of factors
xf <- lapply(as.factor(letters[1:3]), identity)
# vector of factors
unlist(xf, recursive = FALSE)
# list of integers
purrr::flatten(xf)
# vector of integers, converted to character
purrr::flatten_chr(xf)
# list of factors
rlang::flatten(xf)
# error
rlang::flatten_chr(xf) |
For a generic So |
The primary distinction between |
I no longer think is_list <- function(x) typeof(x) == "list" && !is.data.frame(x) && vec_is(x) |
Or |
This would be covered by |
I think you're missing my point — the only things where |
You're right I was confused. |
R implementation of library(vctrs)
library(rlang)
library(purrr)
is_list <- function(x) {
inherits(x, "list")
}
# - `x` must be a list as defined by `is_list()`
# - `vec_ptype(flatten(x)) == list()`
flatten <- function(x) {
if (!is_list(x)) {
abort("`x` must be a list or list subclass.")
}
# Gather output size
size <- vec_size(x)
for (i in seq_along(x)) {
elt <- x[[i]]
if (is_list(elt)) {
size <- size + vec_size(elt) - 1L
}
}
# Always returns a list
idx <- 1L
out <- vec_init(list(), n = size)
# If atomic, insert into `out` immediately
# If list, flatten by inserting each element into `out`
for (i in seq_along(x)) {
elt <- x[[i]]
if (is_list(elt)) {
for (j in seq_along(elt)) {
out[[idx]] <- elt[[j]]
idx <- idx + 1L
}
next
}
out[[idx]] <- elt
idx <- idx + 1L
}
out
}
# - `x` must be a list as defined by `is_list()`
# - `vec_ptype(flatten_vec(x)) == ptype %||% vec_ptype_common(!!! flatten(x))`
flatten_vec <- function(x, ptype = NULL) {
x <- flatten(x)
sizes <- map_int(x, vec_size)
size <- sum(sizes)
ptype <- ptype %||% vec_ptype_common(!!! x)
out <- vec_init(ptype, n = size)
pos <- 1L
for (i in seq_along(x)) {
size <- sizes[[i]]
if (size == 0L) {
next
}
idx <- pos + 0L:(size - 1L)
vec_slice(out, idx) <- x[[i]]
pos <- pos + size
}
out
}
flatten_int <- function(x) {
flatten_vec(x, ptype = integer())
} With # - return value of flatten() is a list
# - flatten() must take a list as input
df <- data.frame(x = 1:2)
flatten(1)
#> Error: `x` must be a list or list subclass.
flatten(df)
#> Error: `x` must be a list or list subclass.
flatten(list(1))
#> [[1]]
#> [1] 1
flatten(list(df))
#> [[1]]
#> x
#> 1 1
#> 2 2
flatten(list(1, list(1)))
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 1
flatten(list(1, list(1:2, 2:3), list(3:4)))
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 1 2
#>
#> [[3]]
#> [1] 2 3
#>
#> [[4]]
#> [1] 3 4
# flattens just 1 level
flatten(list(1, list(list(1))))
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [[2]][[1]]
#> [1] 1 With # flatten_int() is a flatten() followed by insertion into an integer vector
# output size is determined after the flatten()
flatten_int(1)
#> Error: `x` must be a list or list subclass.
flatten_int(list(1))
#> [1] 1
flatten_int(list("x"))
#> Error: No common type for `value` <character> and `x` <integer>.
flatten_int(list(1, list(1)))
#> [1] 1 1
flatten_int(list(1, list(1:5, 2:3)))
#> [1] 1 1 2 3 4 5 2 3
# only 1 layer of flattening is allowed
flatten_int(list(1, list(list(1))))
#> Error: No common type for `value` <list> and `x` <integer>. Generic flatten_vec(list(1))
#> [1] 1
flatten_vec(list(1, list(2, 1:5)))
#> [1] 1 2 1 2 3 4 5
flatten_vec(list(Sys.Date(), list(Sys.Date() + 0:2, Sys.Date())))
#> [1] "2019-10-30" "2019-10-30" "2019-10-31" "2019-11-01" "2019-10-30"
flatten_vec(list(df, list(df, df)))
#> x
#> 1 1
#> 2 2
#> 3 1
#> 4 2
#> 5 1
#> 6 2 |
i.e. should
flatten(x, .type = foo)
be equivalent tovec_c(!!!x, .type = foo)
or should it be equivalent tosimplify()
?The text was updated successfully, but these errors were encountered: