Reputation: 665
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
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
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