I have a matrix like
[,1] [,2]
[1,] 1 3
[2,] 4 6
[3,] 11 12
[4,] 13 14
I want to convert this matrix to a vector
Throwing this one here, it uses base R and should be somewhat fast since the inevitable loop is handled by rep
:
zero.lengths <- m[,1] - c(0, head(m[,2], -1)) - 1
one.lengths <- m[,2] - m[,1] + 1
rep(rep(c(0, 1), nrow(m)),
as.vector(rbind(zero.lengths, one.lengths)))
Or another solution using sequence
:
out <- integer(m[length(m)]) # or `integer(20)` following OP's edit.
one.starts <- m[,1]
one.lengths <- m[,2] - m[,1] + 1
one.idx <- sequence(one.lengths) + rep(one.starts, one.lengths) - 1L
out[one.idx] <- 1L
@ Arun's answer seems better.
Now that I understand the problem (or do I?). Here is a solution in base R that makes use of the idea that only contiguous sequences of zeroes need to be kept.
find.ones <- function (mat) {
ones <- rep(0, max(mat))
ones[c(mat)] <- 1
ones <- paste0(ones, collapse="")
ones <- gsub("101", "111", ones)
ones <- as.numeric(strsplit(ones, "")[[1]])
ones
}
On the OP's original example:
m <- matrix(c(1, 3, 4, 6, 11, 12, 13, 14), ncol=2, byrow=TRUE)
find.ones(m)
[1] 1 1 1 1 1 1 0 0 0 0 1 1 1 1
To benchmark the solution, let's make a matrix big enough:
set.seed(10)
m <- sample.int(n=1e6, size=5e5)
m <- matrix(sort(m), ncol=2, byrow=TRUE)
head(m)
[,1] [,2]
[1,] 1 3
[2,] 4 5
[3,] 9 10
[4,] 11 13
[5,] 14 18
[6,] 22 23
system.time(ones <- find.ones(m))
user system elapsed
1.167 0.000 1.167
Here's an answer using IRanges
package:
require(IRanges)
xx.ir <- IRanges(start = xx[,1], end = xx[,2])
as.vector(coverage(xx.ir))
# [1] 1 1 1 1 1 1 0 0 0 0 1 1 1 1
If you specify a min
and max
value of your entire vector length, then:
max.val <- 20
min.val <- 1
c(rep(0, min.val-1), as.vector(coverage(xx.ir)), rep(0, max.val-max(xx)))