WetlabStudent
WetlabStudent

Reputation: 2606

R: How to extract sets of multidimensional array values according to another matrix

Suppose I have a 4 dimensional n x n x n x n array A. A is a distance matrix, such that A[i,j,l,k] is the distance from location i,j to location pair l,k. Suppose I have an nxn matrix of location types T, lets say the types can be 0, 1, or 2, so T[i,j]=2 means the i,jth location is type 2. What is the easiest way to extract all the [i,j,l,k] entries of A such that T[i,j]=2 and T[l,k]=1, meaning the distances of all paths from a type 1 location to a type 2 location.

My thought was to use something like

type.0 = which(T == 0, arr.ind=T) 
type.1 = which(T == 1, arr.ind=T)
type.2 = which(T == 2, arr.ind=T)

But the problem is that because A is four dimensional, the way R does its indexing its not like you can just do A[type.0,type.1]. Of course I could do it with loops, but is there a better way of doing it.

I couldn't find a past answer on here, but its possible I missed something.

Here is a simple test case with two types 0 and 1, a 2x2 lattice of locations (1,1), type 0 (1,2), type 0, (2,1), type 1, and (2,2) type 1.

A = array(c(0,1,1,1.4,1,0,1.4,1,1,1.4,0,1,1.4,1,1,0), dim = c(2, 2, 2, 2))
T = matrix(c(0,1,0,1),2,2)

I want all the distances from a type 0 cell to a type 1 cell

Upvotes: 0

Views: 798

Answers (2)

WetlabStudent
WetlabStudent

Reputation: 2606

My guess is that there is a more elegant way of doing this. Its inspired by DWin's solution but takes care of all potential combinations of getting from a type 0 to a type 1 cell. Let me know if you guys think of a better way

> type
     [,1] [,2] [,3]
[1,]    0    0    1
[2,]    0    1    0



type.0 = which(type == 0, arr.ind=T) #locations of type 0 cells
type.1 = which(type == 1, arr.ind=T) #locations of type 1 cells

nlocs0 = length(type.0[,1]) #number of locations of type 0
nlocs1 = length(type.1[,1]) #number of locations of type 1

reploc0 = rbind( do.call(rbind, rep(list(type.0), nlocs1)) ) #rbinded on top of itself nloc1 times
reploc1 = rbind( do.call(rbind, rep(list(type.1[1,]), nlocs0)) ) #rbinding the first location of type.1 on top of itself nlocs0 times


if(nlocs1>1){
  for(i in 2:nlocs1){
    reploc1 = rbind( rbind( do.call(rbind, rep(list(type.1[i,]), nlocs0)) ), reploc1)
  } 
}

d0_1 = A[cbind(reploc0,reploc1)]

Upvotes: 1

IRTFM
IRTFM

Reputation: 263411

I guess you have changed the request from the one stated in the first paragraph. See if this answers the second version.

 A [ cbind( which(T == 0, arr.ind=TRUE), which(T == 1, arr.ind=TRUE) )]
#[1] 1 1

(At first I thought you might need abind but cbind works fine.)

Upvotes: 1

Related Questions