In base R, sapply
has a safer (and sometimes faster) variant called vapply
. mapply
is a multivariate version of sapply
.
I am running into an edge case issue when using mapply
(length-0 input to mapply
(not to FUN
) yields a list()
instead of integer(0)
).
Is there an vapply
equivalent of mapply
that allows to specify FUN.VALUE
(the expected return value type/dimension)?
If not, what is the the recommended pattern in those situations?
A toy example:
size_of_union <- function(A, B) length(union(A, B))
# normal case:
x <- list(1:3, 2, 3)
y <- list(3, 2, numeric(0))
mapply(size_of_union, x, y)
#> [1] 3 1 1
# edge-case:
x <- integer(0)
y <- integer(0)
mapply(size_of_union, x, y)
#> list() # integer(0) would be desired here
A more contrived toy example:
range_of_intersect <- function(A, B) range(intersect(A, B))
x <- list(1:3, 2, 3)
y <- list(3, 2, numeric(0))
mapply(range_of_intersect, x, y)
#> Warning in min(x): no non-missing arguments to min; returning Inf
#> Warning in max(x): no non-missing arguments to max; returning -Inf
#> [,1] [,2] [,3]
#> [1,] 3 2 Inf
#> [2,] 3 2 -Inf
x <- numeric(0)
y <- numeric(0)
mapply(range_of_intersect, x, y)
#> list() # structure(numeric(0), .Dim = c(2L, 0L)) would be desired
For your first case you might use as.integer(Map(size_of_union, x, y))
More generally you can still use vapply()
but you'll need to loop on the index rather than on parallel vectors :
size_of_union <- function(A, B) length(union(A, B))
x <- list(1:3, 2, 3)
y <- list(3, 2, numeric(0))
vapply(seq_along(x), function(i) size_of_union(x[[i]], y[[i]]), integer(1))
#> [1] 3 1 1
x <- integer(0)
y <- integer(0)
vapply(seq_along(x), function(i) size_of_union(x[[i]], y[[i]]), integer(1))
#> integer(0)
range_of_intersect <- function(A, B) range(intersect(A, B))
x <- list(1:3, 2, 3)
y <- list(3, 2, numeric(0))
res <- vapply(seq_along(x), function(i) range_of_intersect(x[[i]], y[[i]]), numeric(2))
#> Warning in min(x): no non-missing arguments to min; returning Inf
#> Warning in max(x): no non-missing arguments to max; returning -Inf
res
#> [,1] [,2] [,3]
#> [1,] 3 2 Inf
#> [2,] 3 2 -Inf
dput(res)
#> structure(c(3, 3, 2, 2, Inf, -Inf), dim = 2:3)
x <- numeric(0)
y <- numeric(0)
res <- vapply(seq_along(x), function(i) range_of_intersect(x[[i]], y[[i]]), numeric(2))
res
#>
#> [1,]
#> [2,]
dput(res)
#> structure(numeric(0), dim = c(2L, 0L))
Created on 2023-07-04 with reprex v2.0.2