Reputation: 437
Suppose I have a 5 x 5 matrix in R as follows:
[,1] [,2] [,3] [,4] [,5]
1 0 1 1 0 1
2 1 0 0 1 0
3 0 0 0 1 0
4 1 0 1 0 1
5 1 0 0 0 0
I would like to re-format this matrix into the following structure:
For each row, list the row number and every associated column index containing element 1. For example, if we use the matrix above, we get:
1, 2, 3, 5
2, 1, 4
3, 4
4, 1, 3, 5
5, 1
Upvotes: 2
Views: 110
Reputation: 887108
An option is split
with(as.data.frame(which(m == 1, arr.ind = TRUE)), split(col, row))
#$`1`
#[1] 1 2 4 5
#$`2`
#[1] 1 2 3 4
#$`3`
#[1] 3 5
#$`4`
#[1] 1 2 5
#$`5`
#[1] 1 2 4
Or with tapply
tapply(as.logical(m), row(m), FUN = which)
#$`1`
#[1] 1 2 4 5
#$`2`
#[1] 1 2 3 4
#$`3`
#[1] 3 5
#$`4`
#[1] 1 2 5
#$`5`
#[1] 1 2 4
Or using split
with row
split(m * col(m), row(m))
and to remove the 0's
lapply(split(m * col(m), row(m)), setdiff, 0)
NOTE: All the solutions work.
m <- structure(c(1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1,
0, 0, 1, 1, 0, 1, 1, 0), .Dim = c(5L, 5L))
Upvotes: 0
Reputation: 26343
A second option using which
and aggregate
out <- aggregate(col ~ row, which(m == 1, arr.ind = TRUE), c)
out
# row col
#1 1 1, 2, 4, 5
#2 2 1, 2, 3, 4
#3 3 3, 5
#4 4 1, 2, 5
#5 5 1, 2, 4
(not sure if this is your expected output though)
str(out)
#'data.frame': 5 obs. of 2 variables:
# $ row: int 1 2 3 4 5
# $ col:List of 5
# ..$ 1: int 1 2 4 5
# ..$ 2: int 1 2 3 4
# ..$ 3: int 3 5
# ..$ 4: int 1 2 5
# ..$ 5: int 1 2 4
data
Kindly taken from @Telepresence
set.seed(42)
m = matrix(sample(0:1, 25, TRUE), 5, 5)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 1 0 1 1
#[2,] 1 1 1 1 0
#[3,] 0 0 1 0 1
#[4,] 1 1 0 0 1
#[5,] 1 1 0 1 0
Upvotes: 1
Reputation: 629
set.seed(42)
m = matrix(sample(0:1, 25, TRUE), 5, 5)
apply(m, 1, function(x) which(x == 1))
#[[1]]
#[1] 1 2 4 5
#[[2]]
#[1] 1 2 3 4
#[[3]]
#[1] 3 5
#[[4]]
#[1] 1 2 5
#[[5]]
#[1] 1 2 4
Upvotes: 2