jmb
jmb

Reputation: 665

Subset parts of array with dynamic dimension

I would like to subset an array with a dynamic number of dimensions k.

Take the example:

A <- array(1:3^4, dim=c(3,3,3,3))

Because the dimensions can vary (not shown here), I cannot simply define a, b, c, d and make the query via

a <- 1:2; b <- 2; c <- 2:3; d = 1
A[a, b, c, d]

Here has been shown that if one would like to subset only a single element, one can go about it like this:

e <- 1; f <- 2; g <- 3; h <- 1
A[matrix(c(e, f, g, h), nrow = 1)]

This allows me to keep the number of dimensions flexible, but I can only subset single elements, because I cannot represent the sequences a, b, c, d in a matrix.

The desired situation is that I can get the output of

A[a, b, c, d]

without hardcoding the dimensions, i.e. access the array via

A[object]

and the question is basically is this possible and if yes how does 'object' look like.

Any help would be greatly appreciated!

Upvotes: 2

Views: 190

Answers (2)

Jeff Yontz
Jeff Yontz

Reputation: 246

I've run into this before and found this (quick and dirty) way to take arbitrary set vectors and get the data. Arrays let you pass a matrix of values in where each row represents one position in your Array. Thus, I use expand.grid to get me all the combination of the subset vectors I want to look at, and use this fact to get the values I want:

A <- array(1:3^4, dim=c(3,3,3,3))
a <- 1:2; b <- 2; c <- 2:3; d = 1

eg<- expand.grid(a,b,c,d)
mat <- as.matrix(eg)

print(A[mat]) 
[1] 13 14 22 23

Upvotes: 1

alistaire
alistaire

Reputation: 43334

If you define object as a list, you can use do.call to use that list as parameters for the subsetting function [. If you include the array as the first item in the list, you can call [ directly:

object <- list(A, a, b, c, d)

do.call(`[`, object)
##      [,1] [,2]
## [1,]   13   22
## [2,]   14   23

If you don't want to include the array (if you have lots of these objects and the array is large, it will require a lot of memory), you can write an anonymous function to just use just the subsetting parameters, not what's being subset:

object <- list(a, b, c, d)

do.call(function(...){A[...]}, object)
##      [,1] [,2]
## [1,]   13   22
## [2,]   14   23

That is actually the exact approach abind::asub takes:

object <- list(a, b, c, d)

abind::asub(A, object)
##      [,1] [,2]
## [1,]   13   22
## [2,]   14   23

Note that parameter matching here is relational, so if one is empty, it will need to contain NULL:

object <- list(NULL, b, c, d)

abind::asub(A, object)
##      [,1] [,2]
## [1,]   13   22
## [2,]   14   23
## [3,]   15   24

Upvotes: 3

Related Questions