I find the behavior of rbind somewhat non-intuitive when it's provided with empty vectors. For example,
rbind(numeric(0), numeric(0), numeric(0))
# [1,]
# [2,]
# [3,]
produces a 3-by-0 matrix, while I would expect the output to be a consistent numeric(0) instead. While it may be fun to debate whether you get "one nothing" or "three nothings" when you add a "nothing" to itself three times, my question is whether it's possible to suppress this behavior? Alternatively, I am looking for another function that can "rbind" matrices, while also producing an object with no rows when none of the inputs have rows.
My approach so far has been to cast numeric(0) to a matrix(0,0,0), which appears to work more consistently with rbind:
rbind(matrix(0,0,0), matrix(0,0,0), matrix(0,0,0))
# <0 x 0 matrix>
High-level picture: I have a function that accepts one or more matrices representing linear constraints, rbinds them as the first step and performs some downstream operations. The number of rows in the rbind output is taken to be the total number of input constraints. I discovered the above behavior when I was removing the last row in an input matrix and accidentally left off drop=FALSE, thus calling my function with a numeric(0) instead of a proper matrix(0,0,0) and getting the wrong total number of constraints, because nrow(rbind(numeric(0))) was returning 1.
CodePudding user response:
I don't think you should expect there to be no rows. From rdocumentation, "numeric is identical to double (and real). It creates a double-precision vector of the specified length with each element equal to 0." So, I don't think it's accurate to say they are "nothings."
If you rbind NULL, which I think is closer to "nothing," you get no rows:
rbind(NULL, NULL, NULL)
returns
NULL
So, to answer the question, no I don't know how it would be possible to bind numeric and get no rows.
CodePudding user response:
From ?rbind:
For
cbind(rbind), vectors of zero length (includingNULL) are ignored unless the result would have zero rows (columns), for S compatibility.
I think it is reasonable, if your use case demands it, to write your own rbind analogue that handles zero-length vectors like 0-by-0 matrices instead of 1-by-0 matrices. Maybe something like this?
rbind0 <- function(..., deparse.level = 1) {
f <- function(x) {
if (length(dim(x)) != 2L && (is.atomic(x) || is.list(x)) && length(x) == 0L) {
x <- vector(typeof(x), 0L)
dim(x) <- c(0L, 0L)
}
x
}
args <- c(lapply(list(...), f), list(deparse.level = deparse.level))
do.call(rbind, args)
}
Errors are thrown in more cases, because these 0-by-0 matrices are subject to rbind's checks for dimensional compatibility. For example:
x <- matrix(rnorm(9L), 3L, 3L)
identical(rbind(x, numeric(0L)), x)
## [1] TRUE
rbind0(x, numeric(0L))
## Error in (function (..., deparse.level = 1) :
## number of columns of matrices must match (see arg 2)
You might consider that desirable behaviour, apart from the error message incorrectly referring to integer(0L) as a matrix. You can add more tests to avoid these errors (or throw different errors) in specific cases, but I don't know that it's worth it. Again, it depends on your use case.
