merv merv - 27 days ago 9
R Question

How to store multidimensional subscript as variable in R

Suppose I have a matrix,

mat <- matrix((1:9)^2, 3, 3)


I can slice the matrix like so

> mat[2:3, 2]
[1] 25 36


How does one store the subscript as a variable? That is, what should
my_sub
be, such that

> mat[my_sub]
[1] 25 36


A
list
gets "invalid subscript type" error. A vector will lose the multidimensionality. Seems like such a basic operation to not have a primitive type that fits this usage.

I know I can access the matrix via vector addressing, which means converting from
[2:3, 2]
to
c(5, 6)
, but that mapping presumes knowledge of matrix shape. What if I simply want
[2:3, 2]
for any matrix shape (assuming it is at least those dimensions)?

Answer Source

Here are some alternatives. They both generalize to higher dimenional arrays.

1) matrix subscripting If the indexes are all scalar except possibly one, as in the question, then:

mi <- cbind(2:3, 2)
mat[mi]

# test
identical(mat[mi],   mat[2:3, 2])
## [1] TRUE

In higher dimensions:

a <- array(1:24, 2:4)
mi <- cbind(2, 2:3, 3)
a[mi]

# test
identical(a[mi],   a[2, 2:3, 3])
## [1] TRUE

It would be possible to extend this to eliminate the scalar restriction using:

L <- list(2:3, 2:3)
array(mat[as.matrix(do.call(expand.grid, L))], lengths(L))

however, in light of (2) which also uses do.call but avoids the need for expand.grid it seems unnecessarily complex.

2) do.call This approach does not have the scalar limitation. mat and a are from above:

L2 <- list(2:3, 1:2)
do.call("[", c(list(mat), L2))

# test
identical(do.call("[", c(list(mat), L2)),   mat[2:3, 1:2])
## [1] TRUE


L3 <- list(2, 2:3, 3:4)
do.call("[", c(list(a), L3))

# test
identical(do.call("[", c(list(a), L3)),   a[2, 2:3, 3:4])
## [1] TRUE

This could be made prettier by defining:

`%[%` <- function(x, indexList) do.call("[", c(list(x), indexList))
mat %[% list(2:3, 1:2)
a %[% list(2, 2:3, 3:4)