RobertHannah89
RobertHannah89

Reputation: 155

Convert vector to array index in R?

Say that we have an array A, that has arbitrary dimension dim(A). Say that we have a coordinate index vector V. Is there any way to access the element of A with coordinates V? Doing something like A[V] doesn't work obviously. If V=c(1,2,3) then A[V] will just give us the 1st, 2nd, and 3rd element of A. What if we want A[1,2,3] instead? If we know dim(A) ahead of time, this is easy obviously. But what if we want to make code that works no matter how many dimensions A has?

Upvotes: 1

Views: 885

Answers (2)

jay.sf
jay.sf

Reputation: 72758

We may use do.call to execute `[`.

v <- c(1, 2, 3)

do.call(`[`, c(list(A), v))
# [1] 22

To assign we have `[<-`.

A <- do.call(`[<-`, c(list(A), v, 99))

Check:

A[,,3]
# , , 3
# 
# [,1] [,2] [,3]
# [1,]   19   99   25
# [2,]   20   23   26
# [3,]   21   24   27

Using @duckmayr's A

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

Upvotes: 3

duckmayr
duckmayr

Reputation: 16920

You can make use of eval(parse()), like so:

foo <- function(A, v) {
    stopifnot(length(v) == length(dim(A)))
    idx <- paste(v, collapse = ", ")
    return(eval(parse(text = paste0("A[", idx, "]"))))
}

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

foo(A, v)
# [1] 22
A[1, 2, 3]
# [1] 22

Update: Assignment

In the comments you also ask about assignment; it looks like you've got it sorted, but in case you or someone else finds it useful, you could use a replacement function:

`foo<-` <- function(A, v, value) {
    stopifnot(length(v) == length(dim(A)))
    stopifnot(is.atomic(value) & length(value) == 1)
    idx <- paste(v, collapse = ", ")
    eval(parse(text = paste0("A[", idx, "] <- value")))
    return(A)
}

foo(A, v) <- 2
foo(A, v)
# [1] 2

Upvotes: 2

Related Questions