2

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!

Community
  • 1
  • 1
jmb
  • 625
  • 7
  • 11
  • What? `A[1,1,1,1]` works fine. – alistaire Mar 02 '17 at 18:18
  • Yep, and it's unclear because your [example is not reproducible](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610#5963610) with a defined desired output. – alistaire Mar 02 '17 at 18:21
  • @alistaire made it reproducible, hope this helps – jmb Mar 02 '17 at 18:30
  • 1
    Are you looking for something like `do.call(function(...)A[...], list(a, b, c, d))`? What is the structure of `object`, and how could it vary? – alistaire Mar 02 '17 at 18:33
  • @alistaire well you just defined 'object'; I can define any query in a last, so this solves the problem. Do you want to add this as an answer? – jmb Mar 02 '17 at 18:47

2 Answers2

3

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
alistaire
  • 42,459
  • 4
  • 77
  • 117
1

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
Jeff Yontz
  • 246
  • 1
  • 10