Reputation: 223
So I've got a matrix of logical vectors like this :
r=10
c=10
m1 <- matrix(runif(r*c)>0.5, r, c)
> m1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE
[2,] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
[3,] TRUE FALSE FALSE TRUE FALSE TRUE TRUE TRUE TRUE FALSE
[4,] FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE
[5,] TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE FALSE
[6,] TRUE FALSE TRUE FALSE TRUE TRUE FALSE FALSE FALSE TRUE
[7,] FALSE TRUE TRUE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
[8,] FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE TRUE TRUE
[9,] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[10,] TRUE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE TRUE
And a vector like this :
v1 <- round(runif(10,1,10))
> v1
[1] 6 5 7 5 5 4 4 2 1 10
How can I get the 10 indexes > v1 of first TRUE value of each column of m1 ?
So for this example, I want to get this vector :
[1] 9 7 8 NA 6 5 7 3 3 NA
Thanks for your help
Upvotes: 3
Views: 495
Reputation: 93813
Get the row/column indices for each TRUE
using which
. The code inside which
uses the combination of sweep
to calculate if it is a higher row count, and the original TRUE/FALSE mat
object. Then, these indices are subset to the first match in each column using match
, which will return NA
when there is no value in the column.
# using Maurits' data
matsel <- which(sweep(row(mat), 2, v1, FUN=`>`) & mat, arr.ind=TRUE)
matsel[,"row"][match(seq_len(ncol(mat)), matsel[,"col"])]
#[1] NA NA 3 5 8 2 9 8 2 2
This should scale very nicely too, as it avoids any looping over columns or rows. The only thing to watch would be matsel
becoming big and hogging your memory as it stores every TRUE
value's location.
Upvotes: 0
Reputation: 3233
Is it what you want?
r=10
c=10
set.seed(42)
m1 <- matrix(runif(r*c)>0.5, r, c)
set.seed(314)
v1 <- round(runif(10,1,10))
out = sapply(1:10, function(i)
{
v = v1[i]
r = m1[v:10,i]
j = which(r)[1] + v - 1
})
out
My input (reproducible with the seed)
> m1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] TRUE FALSE TRUE TRUE FALSE FALSE TRUE FALSE TRUE TRUE
[2,] TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
[3,] FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[4,] TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE
[5,] TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE TRUE
[6,] TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE
[7,] TRUE TRUE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE
[8,] FALSE FALSE TRUE FALSE TRUE FALSE TRUE FALSE FALSE TRUE
[9,] TRUE FALSE FALSE TRUE TRUE FALSE TRUE TRUE FALSE TRUE
[10,] TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE
> v1
[1] 2 3 8 3 3 4 3 4 6 8
My output
> out
[1] 4 6 10 4 4 6 4 6 NA 9
Upvotes: 1
Reputation: 50678
One option is to use mapply
. Here is a reproducible example using a fixed random seed.
set.seed(2017)
r <- 10
c <- 10
m1 <- matrix(runif(r*c) > 0.5, r, c)
v1 <- round(runif(10,1,10))
mapply(function(x, y) { idx <- which(x == TRUE); idx[idx > y][1]}, as.data.frame(m1), v1, USE.NAMES = F)
#[1] NA NA 3 5 8 2 9 8 2 2
Explanation: For every column of m1
we extract the indices of TRUE
entries in idx
; we then return the first index of idx
that is greater than the column number-matched entry in v1
; if no such number exists, it automatically returns NA
.
Note: In order for mapply
to simultaneously loop over columns of m1
and entries of v1
, we need to convert m1
into a data.frame
.
With the above fixed random seed, the sample is data is
m1
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE FALSE TRUE
# [2,] TRUE FALSE FALSE FALSE TRUE TRUE FALSE TRUE TRUE TRUE
# [3,] FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE TRUE TRUE
# [4,] FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
# [5,] TRUE FALSE FALSE TRUE TRUE TRUE TRUE TRUE FALSE TRUE
# [6,] TRUE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE
# [7,] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
# [8,] FALSE TRUE FALSE FALSE TRUE TRUE FALSE TRUE FALSE FALSE
# [9,] FALSE TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE TRUE
#[10,] FALSE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE FALSE
v1
#[1] 9 10 2 3 6 1 5 6 1 1
Upvotes: 1