How to slice a n dimensional array with a m*(n-i) dimensional matrix?

强颜欢笑 提交于 2019-12-04 20:26:43

I think this is the cleanest way -- making a separate function:

slicem <- function(a,idx,drop=FALSE) do.call(`[`,c(list(a),idx,list(drop=drop)))

# usage for OP's example
a      <- array(1:27, c(3,3,3))    
idx    <- list(1:2, TRUE, 1:2)
slicem(a,idx)

which gives

, , 1

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8

, , 2

     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17

You have to write TRUE for each dimension that you aren't selecting from.


Following the OP's new expectations...

library(abind)
nistfun <- function(a,list_o_idx,drop=FALSE){
  lens <- lengths(list_o_idx)
  do.call(abind, lapply(seq.int(max(lens)), function(i)
    slicem(a, mapply(`[`, list_o_idx, pmin(lens,i), SIMPLIFY=FALSE), drop=drop)
  ))
}

# usage for OP's new example
nistfun(a, idx)

# , , 1
# 
#      [,1] [,2] [,3]
# [1,]    1    4    7
# 
# , , 2
# 
#      [,1] [,2] [,3]
# [1,]   11   14   17

Now, any non-TRUE indices must have the same length, since they will be matched up.

abind is used here instead of rbind (see an earlier edit on this answer) because it is the only sensible general way to think about slicing up an array. If you really want to drop dimensions, it's quite ambiguous which should be dropped and how, so the vector alone is returned:

nistfun(a, idx, drop=TRUE)
# [1]  1  4  7 11 14 17

If you want to throw this back into an array of some sort, you can do that after the fact:

matrix( nistfun(a, idx), max(lengths(idx)), dim(a)[sapply(idx,isTRUE)]), byrow=TRUE)

#      [,1] [,2] [,3]
# [1,]    1    4    7
# [2,]   11   14   17
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!