-
Couldn't load subscription status.
- Fork 71
Open
Labels
Description
It has different invariants than the purrr one, but it seems very well grounded in vctrs theory
https://github.com/DavisVaughan/cross/blob/95a27b17bfb123c8082c54eb972f703a8feccb4a/R/run.R#L249
- Can probably get away with early recycling/casting if we give
vec_interleave()acallargument. - Might not even really need a
sizeargument? "All list elements must be size 1 or the same size" seems good enough? i.e. the same reasonvec_interleave()doesn't have one.
# Transpose a list of vectors
#
# Invariants:
#
# - `x` must be a list
# - Names of `x` are used in error messages, but are then discarded
# - Each element of `x` is coerced to the common type of the elements, or
# `ptype`
# - Each element of `x` is recycled to the common size of the elements, or
# `size`
# - Output is a list of size `size`. Each element is a vector of size `x_size`
# and type `ptype`.
list_transpose <- function(
x,
...,
ptype = NULL,
size = NULL,
x_arg = caller_arg(x),
error_call = caller_env()
) {
obj_check_list(x, arg = x_arg, call = error_call)
x_size <- vec_size(x)
ptype <- vec_ptype_common(
!!!x,
.ptype = ptype,
.arg = x_arg,
.call = error_call
)
size <- vec_size_common(
!!!x,
.size = size,
.arg = x_arg,
.call = error_call
)
x <- vec_cast_common(
!!!x,
.to = ptype,
.arg = x_arg,
.call = error_call
)
x <- vec_recycle_common(
!!!x,
.size = size,
.arg = x_arg,
.call = error_call
)
# Don't want outer names after doing common type / size determination,
# could use `.name_spec = "inner"` with new vctrs in `vec_interleave()`
x <- unname(x)
# Combine pieces of size `size` into one big vector via interleaving
x <- vec_interleave(!!!x, .ptype = ptype)
# Chop the one big vector into transposed pieces of size `x_size`
x <- vec_chop(x, sizes = vec_rep(x_size, times = size))
x
}Ideal implementation is probably more like this. Need an internal list_interleave().
# TODO: Handle `NULL` list elements well? Is that even well defined?
# TODO: Handle empty `list()`. `list_interleave()` returns `NULL` but would
# be nice if this returned `unspecified()` for further use in `vec_chop()`.
# Need to handle divide by 0 size issue too.
list_transpose <- function(
x,
...,
ptype = NULL,
x_arg = caller_arg(x),
error_call = caller_env()
) {
# - Does `obj_check_list()`
# - Does `list_check_all_vectors()`
# - Takes common size, recycles size 1 inputs
out <- list_interleave(
x,
.ptype = ptype,
.name_spec = "inner",
.x_arg = x_arg,
.error_call = error_call
)
x_size <- vec_size(x)
out_size <- vec_size(out)
elt_size <- out_size / x_size
# Chop the one big vector into transposed pieces of size `x_size`
out <- vec_chop(out, sizes = vec_rep(x_size, times = elt_size))
out
}