Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check that a vector is contained in a matrix in R

I can't believe this is taking me this long to figure out, and I still can't figure it out.

I need to keep a collection of vectors, and later check that a certain vector is in that collection. I tried lists combined with %in% but that doesn't appear to work properly.

My next idea was to create a matrix and rbind vectors to it, but now I don't know how to check if a vector is contained in a matrix. %in appears to compare sets and not exact rows. Same appears to apply to intersect.

Help much appreciated!

like image 564
dmkc Avatar asked Dec 21 '22 20:12

dmkc


1 Answers

Do you mean like this:

wantVec <- c(3,1,2)
myList <- list(A = c(1:3), B = c(3,1,2), C = c(2,3,1))
sapply(myList, function(x, want) isTRUE(all.equal(x, want)), wantVec)
## or, is the vector in the set?
any(sapply(myList, function(x, want) isTRUE(all.equal(x, want)), wantVec))

We can do a similar thing with a matrix:

myMat <- matrix(unlist(myList), ncol = 3, byrow = TRUE)
## As the vectors are now in the rows, we use apply over the rows
apply(myMat, 1, function(x, want) isTRUE(all.equal(x, want)), wantVec)
## or
any(apply(myMat, 1, function(x, want) isTRUE(all.equal(x, want)), wantVec))

Or by columns:

myMat2 <- matrix(unlist(myList), ncol = 3)
## As the vectors are now in the cols, we use apply over the cols
apply(myMat, 2, function(x, want) isTRUE(all.equal(x, want)), wantVec)
## or
any(apply(myMat, 2, function(x, want) isTRUE(all.equal(x, want)), wantVec))

If you need to do this a lot, write your own function

vecMatch <- function(x, want) {
    isTRUE(all.equal(x, want))
}

And then use it, e.g. on the list myList:

> sapply(myList, vecMatch, wantVec)
    A     B     C 
FALSE  TRUE FALSE 
> any(sapply(myList, vecMatch, wantVec))
[1] TRUE

Or even wrap the whole thing:

vecMatch <- function(x, want) {
    out <- sapply(x, function(x, want) isTRUE(all.equal(x, want)), want)
    any(out)
}

> vecMatch(myList, wantVec)
[1] TRUE
> vecMatch(myList, 5:3)
[1] FALSE

EDIT: Quick comment on why I used isTRUE() wrapped around the all.equal() calls. This is due to the fact that where the two arguments are not equal, all.equal() doesn't return a logical value (FALSE):

> all.equal(1:3, c(3,2,1))
[1] "Mean relative difference: 1"

isTRUE() is useful here because it returns TRUE iff it's argument is TRUE, whilst it returns FALSE if it is anything else.

like image 156
Gavin Simpson Avatar answered Jan 18 '23 17:01

Gavin Simpson