RSzT
RSzT

Reputation: 337

array: subset element from one dimension by name dynamically

I have following array (in an example 3-dimensional, but it can be 3+ dims):

a <- c('a1', 'a2', 'a3')
b <- c('bb', 'bbb')
c <- c('C', 'CC', 'CCC')

dimNa <- list('a' = a, 'b' = b, 'c' = c)

outputArray <- array(NA,
                     unname(sapply(dimNa, function(x) length(x), simplify = T)),
                     unname(dimNa))

I can subset it using name from one dimension manually, like:

> outputArray[,'bb',]
    C CC CCC
a1 NA NA  NA
a2 NA NA  NA
a3 NA NA  NA

or

> outputArray[,,'CCC']
   bb bbb
a1 NA  NA
a2 NA  NA
a3 NA  NA

The question is how to pass a vector (or sth else? - in this case ,'bb', and ,,'CCC') to [, so I can write a function to generate this automatically (assuming that I can extract info regarding which name is stored in which dimension - names are unique and I can get this info from dimnames(outputArray) )? Just like I mentioned array can be 3+ dims.

Edit: I would like to subset by name only from one dimension. So outputArray[,'bb',] or outputArray[,,'CCC'], not outputArray[,'bb','CCC'], but solution should work for more dimensions.

Upvotes: 0

Views: 219

Answers (2)

RSzT
RSzT

Reputation: 337

Thanks to How to pass/use string in [ to subset I was able to create following function (using abind::asub):

library("abind")

subsetElement <- function(inputArray, whichIdx){

  whichDim <- NULL
  dimNames <- dimnames(inputArray)

  for (dn in seq_len(length(dimNames))){
    if (whichIdx %in% dimNames[[dn]]){
      whichDim <- dn
      break
    }
  }

  if(!is.null(whichDim)){
    return(abind::asub(inputArray, whichIdx, whichDim))
  }

  return(NULL)
}

It works only if indices are unique.

> subsetElement(outputArray, 'bb')
    C CC CCC
a1 NA NA  NA
a2 NA NA  NA
a3 NA NA  NA

> subsetElement(outputArray, 'C')
   bb bbb
a1 NA  NA
a2 NA  NA
a3 NA  NA

Upvotes: 1

akrun
akrun

Reputation: 887078

We can create the three dimensional index and use Map to extract for each of the cases

d1 <- dim(outputArray)
Map(function(i,j,k) outputArray[i,j,k], 
   list(seq_len(d1[1])), list('bb', seq_len(d1[2])), list(seq_len(d1[3]), 'CCC'))
#[[1]]
#    C CC CCC
#a1 NA NA  NA
#a2 NA NA  NA
#a3 NA NA  NA

#[[2]]
#   bb bbb
#a1 NA  NA
#a2 NA  NA
#a3 NA  NA

Upvotes: 0

Related Questions