[R] List to Array: How to establish the dimension of the array

Brian Diggs diggsb at ohsu.edu
Thu Jan 26 17:45:50 CET 2012


Please include the context of the discussion in your responses.  See 
inline below.

On 1/24/2012 11:33 PM, Ajay Askoolum wrote:
> Thanks you,
>
> I can get the length of aa with length(unlist(aa)). If aa has 4
> dimensions, I imagine I'd need to do
>
> max(sapply(aa,sapply,sapply,length)

Correct.

> How can I do this in a generic way? That is in a loop. I am clear
> about the exit condition for the loop.

By generic, I assume that you mean without knowing the depth of the 
lists (that is, "dimensions") to begin with?

> d<-1
>
>
> start loop
>
> if d = length(unlist(aa)) then exit loop

Note that length(unlist(aa)) will only equal the product of the 
dimensions if the data is "regular."  That is, there is an entry for 
every combination of indices (within the dimensions).

> else
>      d<-d *<expr>
>
>
> How do I construct<expr>  such that it does
>
>> d<- d * length(aa)                      # first pass
>
>> d<- d * max(sapply(aa, length))         # second pass
>
>> d<- d * max(sapply(aa, sapply, length)) # third pass
>
>
>> # ? #                                    # fourth path etc
>
>

> (Apologies for the pseudo code describing the loop; I am not near a
> machine with R)

I don't really understand this.

> One way I can thing of is to create a loop counter variable, say
> lc<-1 and to increment it within the loop and then use a switch
> statement to execute the appropriate expression. This sems like a
> kludge to me.
>
> Is there a neater way?

If you are trying to get back a vector of the dimensions, then this 
would work:

dimRecursiveList <- function(l) {
	if (class(l) == "list") {
		c(length(l), dimRecursiveList(l[[1]]))
	} else {
		NULL
	}
}

 From previous context:

aa <- list(list(list(37531.52, 62787.32, 5503.184, 33832.8),
                 list(20469.60, 27057.27, 51160.25, 45165.24),
                 list(957.932,  21902.94, 37531.52, 62787.32)),
            list(list(5503.184, 33832.8,  20469.6,  27057.27),
                 list(51160.25, 45165.24, 957.932,  21902.94),
                 list(37531.52, 62787.32, 5503.184, 33832.8)))

Which then gives

 > dimRecursiveList(aa)
[1] 2 3 4

In this case, the data is regular, so

 > Reduce(`*`, dimRecursiveList(aa)) == length(unlist(aa))
[1] TRUE

If the data are not regular, and you want the dimension to be the 
largest, then it is more complicated (due to bookkeeping)

dimRecursiveListIrregular <- function(l) {
   if (class(l) == "list") {
     dims <- sapply(l, dimRecursiveListIrregular)
     if (is.null(dim(dims))) {
       if (all(is.na(dims))) {
         length(l)
       } else {
         c(length(l), max(dims, na.rm=TRUE))
       }
     } else {
       c(length(l), apply(dims, 1, max, na.rm=TRUE))
     }
   } else {
     NA
   }
}

If the data are regular, then it is better to convert this to an array. 
This function will do it for arbitrary depth

RecursiveListToArray <- function(l) {
   if(class(l) == "list") {
     laply(l, RecursiveListToArray)
   } else {
     l
   }
}

 > aaa <- RecursiveListToArray(aa)
 > dim(aaa)
[1] 2 3 4

-- 
Brian S. Diggs, PhD
Senior Research Associate, Department of Surgery
Oregon Health & Science University



More information about the R-help mailing list