Search code examples
arraysrsubsetdimension

R Array subsetting: flexible use of drop


As it has been noticed in Subsetting R array: dimension lost when its length is 1 R drops every dimension when subsetting and its length is 1.

The drop property helps avoid that. I need a more flexible way to subset :

> arr = array(1, dim= c(1,2,3,4))
> dim(arr[,,1,])
[1] 2 4
> dim(arr[,,1,,drop=F])
[1] 1 2 1 4

I want a way to subset by dropping the 3rd dimension (actually the dimension where I put the subset 1) and keepping the 1st dimension (the dimensions where no subset is put).

It should return an array with dimension = 1 2 4

My issue is that I started coding with an array with no dimension = 1, but when coming to deal with some cases where a dimension is 1, it crashes. The function I need provides a way to deal with the array as if the dimension is not 1.


Solution

  • Two ways to do this, either use adrop from package abind, or build a new array with the dimensions you choose, after doing the subsetting.

    library(abind)
    arr  <- array(sample(100, 24), dim=c(1, 2, 3, 4))
    arr2 <- adrop(arr[ , , 1, , drop=FALSE], drop=3)
    dim(arr2)
    arr3 <- array(arr[ , , 1 , ], dim=c(1,2,4))
    identical(arr2, arr3)
    

    If you want a function that takes a single specified margin, and a single index of that margin, and drops that margin to create a new array with exactly one fewer margin, here is how to do it with abind:

    specialsubset <- function(ARR, whichMargin, whichIndex) {
       library(abind)
       stopifnot(length(whichIndex) == 1, length(whichMargin) == 1, is.numeric(whichMargin))
       return(adrop(x = asub(ARR, idx = whichIndex, dims = whichMargin, drop = FALSE), drop = whichMargin))
    }
    arr4 <- specialsubset(arr, whichMargin=3, whichIndex=1)
    identical(arr4, arr2)