3

I have a multidimensional array, created in the following way:

my_array <- array(seq(12), dim=my_dims, dimnames=my_dimnames)

where "my_dims" is a numeric vector and "my_dimnames" is a list of character vectors, with lengths corresponding to the dimensions specified in "mydims", for example:

my_dims <- c(2, 3, 2)
my_dimnames <- list(c("D_11", "D_12"), c("D_21", "D_22", "D_23"), c("D_31", "D_32"))

So that "my_array" looks something like this:

, , D_31

     D_21 D_22 D_23
D_11    1    3    5
D_12    2    4    6

, , D_32

     D_21 D_22 D_23
D_11    7    9   11
D_12    8   10   12

Additionally, I have a character vector containing specific values of each dimension:

my_values <- c("D_11", "D_21", "D_32")

Now, from this question: R - how to get a value of a multi-dimensional array by a vector of indices I learned that I can read and write values from and to specific cells in "my_array" using matrix indexing, like this:

my_array[matrix(my_values, 1)]

to get the value "7" and

my_array[matrix(my_values, 1)] <- 1

to set that same cell to value "1"

What I don't understand, though, is how I can get all values from a specific dimension from "my_array", given specific values for all other dimensions using this method.

For example: how can I get a vector containing all values of the first dimension with fixed values "D_21" and "D_32" for the second and third dimension? So in this case what I try to extract would be a vector of the form:

c(7, 8)

How do I need to adjust the matrix indexing to achieve this result?

Thanks a lot in advance!

4
  • 1
    Make use of the dimnames of your array? Something like: my_array[cbind(dimnames(my_array)[[1]], "D_21", "D_32")] perhaps? Commented Jan 14, 2016 at 17:07
  • How do "my_values" look in the case that you want all of a dimension? Commented Jan 14, 2016 at 17:59
  • @alexis_laz: that's exactly what I want to know. I hoped there was something similar to selecting all elements of a data.frame by leaving a dimension empty (like all rows for cells c1 and c2 in data frame df using "df[, c(c1, c2)]"). Is there a similar way to formulate a list or vector like "my_values" to generate a matrix for indexing? Commented Jan 15, 2016 at 15:49
  • @scholt : From the QA you've linked you can use do.call("[", ... To simulate the missing argument in a dimensions use substitute(). E.g. do.call("[", c(list(my_array), list("D_11", "D_23", "D_31"))); do.call("[", c(list(my_array), list(substitute(), "D_23", "D_31"))); do.call("[", c(list(my_array), list("D_12", substitute(), "D_31", drop = FALSE))) etc. Your arguments for do.call need to be in a "list"; e.g. for "my_values" you'd need as.list(my_values). Commented Jan 15, 2016 at 15:57

1 Answer 1

1

I don't know if something like this already exists, but as mentioned in the comments, you can make use of the dimnames of your array.

It would be best if your "my_values" object were a list, as that would give you a lot of flexibility that you won't have with a vector.

Here's a possible approach. Create a function that creates a matrix that can be used to subset from your array. The function would essentially look something like this:

mat_maker <- function(array, vals) {
  x <- sapply(vals, is.null)
  vals[x] <- dimnames(array)[x]
  as.matrix(expand.grid(vals))
}

The extraction function would be like this. (Most likely, you would just roll both of these functions together, but I thought I would share them here separately so that you can see what is going on.)

array_extractor <- function(array, vals) {
  array[mat_maker(array, vals)]
}

Now, try the following examples out. Notice that the "vals" argument is a list, and that NULL is used for dimensions that are not being specified.

## All values where rowname == "D_11"
mat_maker(my_array, list("D_11", NULL, NULL))
#      Var1   Var2   Var3  
# [1,] "D_11" "D_21" "D_31"
# [2,] "D_11" "D_22" "D_31"
# [3,] "D_11" "D_23" "D_31"
# [4,] "D_11" "D_21" "D_32"
# [5,] "D_11" "D_22" "D_32"
# [6,] "D_11" "D_23" "D_32"
array_extractor(my_array, list("D_11", NULL, NULL))
# [1]  1  3  5  7  9 11


## All first column values from the second array object
## This is your specific example
mat_maker(my_array, list(NULL, "D_21", "D_32"))
#      Var1   Var2   Var3  
# [1,] "D_11" "D_21" "D_32"
# [2,] "D_12" "D_21" "D_32"
array_extractor(my_array, list(NULL, "D_21", "D_32"))
# [1] 7 8

## First two columns from all array dimensions
array_extractor(my_array, list(NULL, c("D_21", "D_22"), NULL))
# [1]  1  2  3  4  7  8  9 10

An extension of this function would be to put the dimensional attributes (including the names) back into the output. It could look something like this:

extractMe <- function(array, vals) {
  x <- sapply(vals, is.null)
  vals[x] <- dimnames(array)[x]
  temp <- as.matrix(expand.grid(vals))
  `dimnames<-`(`dim<-`(array[temp], lengths(vals)), vals)
}

Here's the usage:

extractMe(my_array, list("D_11", NULL, NULL))
# , , D_31
# 
#      D_21 D_22 D_23
# D_11    1    3    5
# 
# , , D_32
# 
#      D_21 D_22 D_23
# D_11    7    9   11

extractMe(my_array, list(NULL, "D_21", "D_32"))
# , , D_32
# 
#      D_21
# D_11    7
# D_12    8

extractMe(my_array, list(NULL, c("D_21", "D_22"), NULL))
# , , D_31
# 
#      D_21 D_22
# D_11    1    3
# D_12    2    4
# 
# , , D_32
# 
#      D_21 D_22
# D_11    7    9
# D_12    8   10

And, for cases where you want just a vector of the values, just wrap it with c:

c(extractMe(my_array, list(NULL, "D_21", "D_32")))
# [1] 7 8
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much for this solution. It seems to work for me, but actually I was wondering if it was possible to achieve the same goal with onboard functions that come with R. More specifically, I was wondering if there is a way to specify something like a wildcard - I think that is the "NULL" in your solution - in matrix indexing directly. I was always intrigued that you can select whole columns or rows of a data frame in R by just writing something like "df[, c("column_1", "column_2")]" and was wondering if there is something similar for matrix indexing.
@scholt, Yes, there is, but the question remains, how do you go from a flat vector ("my_values") to what you want. Since you're dealing with a 3-dimensional array here, you could do my_array[row, col, third-dimension]. Compare the results of my_array[1, , ]; my_array[, 1, ]; my_array[, , 1].

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.