Bangyou
Bangyou

Reputation: 9816

Assign values to a specific dimension of array in R

I have a multiple dimension array and try to assign values to a specific dimension. Please see codes below for my current method.

# Create a array and fill with NA
set.seed(1)
dim_arr <- seq(2, 10)
arr <- array(NA, dim = dim_arr)

# Add values to the dimension 2 and fill other dimensions
add_dim <- 2

# Generate value
values <- runif(prod(dim_arr[-add_dim]))
# Assign value to position 1 of dimension 2
arr[,1,,,,,,,] <- values

values <- runif(prod(dim_arr[-add_dim]))
# Assign value to position 2 of dimension 2
arr[,2,,,,,,,] <- values

My problem is that the number of dimension (dim_arr) and changed dimension (add_dim) are not fixed. When parameters dim_arr and add_dim are changed, the code "arr[,1,,,,,,,]" is broken which I have to change it every time.

Is there any generic method to improve my codes?

Please let me know if my question is not clear. Thanks for any suggestions.

Upvotes: 3

Views: 1144

Answers (1)

BrodieG
BrodieG

Reputation: 52637

The correct way to do this will be to a call to do.call specifying the full extent of each dimension other than the one you want (e.g. do.call("[<-", list(arr, 1:x, 1:y, 3, values)). The fun way is to take advantage of the mysterious missing object to generate the empty arguments in x[,,,z,,,].

EDIT: a more boring but simpler approach is included at the end as it turns out a single TRUE as an argument is equivalent to the missing argument.

EDIT2: simplified with Hadley's substitute() approach.

replace_dim <- function(arr, rep.val, dim.to.rep, dim.val) {
  dim.list <- replicate(length(dim(arr)), substitute())
  dim.list[dim.to.rep] <- dim.val
  do.call(`[<-`, c(list(arr), dim.list, list(rep.val)))
}
arr <- array(1:8, dim=rep(2, 3))

replace_dim(arr, 555, 3, 1)  # note this doesn't modify `arr`, so you would have to set `arr` to the return value
# , , 1
#      [,1] [,2]
# [1,]  555  555
# [2,]  555  555
# , , 2
#      [,1] [,2]
# [1,]    5    7
# [2,]    6    8

replace_dim(arr, 555, 2, 1)
# , , 1
#      [,1] [,2]
# [1,]  555    3
# [2,]  555    4
# , , 2
#      [,1] [,2]
# [1,]  555    7
# [2,]  555    8

replace_dim(arr, 555, 1, 1)
# , , 1
#      [,1] [,2]
# [1,]  555  555
# [2,]    2    4
# , , 2
#      [,1] [,2]
# [1,]  555  555
# [2,]    6    8

replace_dim(arr, 555, 1, 2)
# , , 1
#      [,1] [,2]
# [1,]    1    3
# [2,]  555  555
# , , 2
#      [,1] [,2]
# [1,]    5    7
# [2,]  555  555  

Also, here we used 555, but you could have used any vector/object that fits the dimensions you are inserting into.

replace_dim_boring <- function(arr, rep.val, dim.to.rep, dim.val) {
  dim.list <- as.list(rep(T, length(dim(arr))))
  dim.list[dim.to.rep] <- dim.val
  do.call(`[<-`, c(list(arr), dim.list, list(rep.val)))
}

Upvotes: 3

Related Questions