Reputation: 303
Am looking at say 3-dimensional array M: M<-dim(3,3,3)
I want to find an efficient way to populate M with the following rule:
M[i,j,k] = i/10 + j^2 + sqrt(k),
ideally without having to write a loop with a for
statemenet.
For clarification, there is a simple way to accomplishing this if M were 2-dimensional. If i wanted to have
M[i,j] = i/10 + j^2,
then i could just do
M<-row(M)/10 + col(M)*col(M)
Is there something equivalent for 3-or-higher dimensional arrays?
Upvotes: 6
Views: 1510
Reputation: 226162
@James's answer is better, but I think the narrow answer to your question (multidimensional equivalent of row()/col()
) is slice.index
...
M<- array(dim=c(3,3,3))
slice.index(M,1)/10+slice.index(M,2)^2+sqrt(slice.index(M,3))
It would be a good idea if someone (I or someone else) posted a suggestion on the r-devel
list to make slice.index
a "See also" entry on ?row
/?col
...
Alternatively (similar to @flodel's new answer):
d <- do.call(expand.grid,lapply(dim(M),seq)) ## create data.frame of indices
v <- with(d,Var1/10+Var2^2+sqrt(Var3)) ## default names Var1, ... Varn
dim(v) <- dim(M) ## reshape into array
Upvotes: 7
Reputation: 89057
You can also use arrayInd
:
M <- array(dim = c(3, 3, 3))
foo <- function(dim1, dim2, dim3) dim1/10 + dim2^2 + sqrt(dim3)
idx <- arrayInd(seq_along(M), dim(M), useNames = TRUE)
M[] <- do.call(foo, as.data.frame(idx))
I feel this approach has potential for less typing as the number of dimensions increases.
Upvotes: 2
Reputation: 263332
Doing it from the "ground up" so to speak.
i <- rep(1:3, times=3*3)
j <- rep(1:3 , times= 3, each=3)
k <- rep(1:3 , each= 3*3)
M <- array( i/10 + j^2 + sqrt(k), c(3, 3, 3))
M
Upvotes: 1
Reputation: 66834
How about using nested outer
s?
outer(1:3/10,outer((1:3)^2,sqrt(1:3),"+"),"+")
, , 1
[,1] [,2] [,3]
[1,] 2.1 5.1 10.1
[2,] 2.2 5.2 10.2
[3,] 2.3 5.3 10.3
, , 2
[,1] [,2] [,3]
[1,] 2.514214 5.514214 10.51421
[2,] 2.614214 5.614214 10.61421
[3,] 2.714214 5.714214 10.71421
, , 3
[,1] [,2] [,3]
[1,] 2.832051 5.832051 10.83205
[2,] 2.932051 5.932051 10.93205
[3,] 3.032051 6.032051 11.03205
Upvotes: 4