6

I'm having a question about indexing 3 dim arrays.

Say I have a 3 dimensional array

x<- c(1:36)
dim(x) <- c(3,4,3) 

Now I want to extract values out of this array according to a matrix holding the 3rd dimension indices for all [i,j] positions.

y <- c(rep(1,4),rep(2,4),rep(3,4))
dim(y) <- c(3,4)

y
      [,1] [,2] [,3] [,4]
[1,]    1    1    2    3
[2,]    1    2    2    3
[3,]    1    2    3    3

So the result should be giving this:

     [,1] [,2] [,3] [,4]
[1,]    1    4   19   34
[2,]    2   17   20   35
[3,]    3   18   33   36

Is there some elegant way to do this? I know how to use two for loops to go over the array, but this is too slow for my data.

2 Answers 2

7

help("[") tells us this:

Matrices and arrays

[...]

A third form of indexing is via a numeric matrix with the one column for each dimension: each row of the index matrix then selects a single element of the array, and the result is a vector.

Thus, we transform your y matrix to a shape that conforms with this.

library(reshape2)
z <- x[as.matrix(melt(y))]
dim(z) <- dim(y)
#     [,1] [,2] [,3] [,4]
#[1,]    1    4   19   34
#[2,]    2   17   20   35
#[3,]    3   18   33   36
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for the help. And yes reading help files is a very good idea. Always. By the way is it possible to use some condition testing in the matrix of indices? like x>3?
5

I'm looking at this as an opportunity for some code golf. It's definitely possible to do this as a one-liner:

> `dim<-`(x[cbind(c(row(y)), c(col(y)), c(y))], dim(y))
     [,1] [,2] [,3] [,4]
[1,]    1    4   19   34
[2,]    2   17   20   35
[3,]    3   18   33   36

As @Roland's answer shows, matrix/array indexing involves creating an n-column matrix and setting the columns equal to row, column, etc. position of each dimension of an n-dimensional array. We can use the row() and col() functions to extract the row and column positions of each element in y:

> row(y)
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    2    2    2    2
[3,]    3    3    3    3
> col(y)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    1    2    3    4
[3,]    1    2    3    4

and y itself gives the third-dimension positions. wrapping each of those in c() turns them into a vector, so that they can be cbind-ed together to create an extraction matrix.

Then, there's just some fun use of dim<-() to fit it all on one line.

4 Comments

Thank you Thomas. I like your ambition. I'm also a big fan of using only base functions when possible. But I have to say I don't understand your fun use of dim. How does that work? What does the backticks do?
@Atomhamster When you do dim(x) <- dim(y), you're actually doing dim<-(x, dim(y)) where "dim<-" is the name of a function. This is useful when you want to use a function like dim<-() or names<-(), etc. without first creating the lefthand-side object. (The backticks just let you call the "dim<-()" function directly, but they're hard to write in this comment markup.)
Thanky you @Thomas for the explanation. Very interesting to know this trick. I guess it could save me some significant number of lines in my functions.
@Atomhamster Another, perhaps more intuitive approach would be from the setter package: cran.r-project.org/web/packages/setter/setter.pdf

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.