rjagsrunjags

How to coerce NESTED list into double without losing the structure (R)


there seem to many answered questions about how to convert a list into a double, but nothing that seems to keep the structure of the list valid.

I have a nested list like that (R output):

my_list

[[1]] 
[1]  1  3  4  8 11 13 17

[[2]] 
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20

[[3]]  
[1]  2 14

Then I pass this list to JAGS in order to iterate over its elements. In the JAGS loop I want to iterate over the first, second and third element and then retrieve the numbers stored in there to be iterated over again in another loop. That means I want to access "1 3 4 8 11 13 17" of the first element and so on.


The code in the JAGS script that I use to iterate is like this:

    for (j in 1:subjects) {  # Subject-loop
          for (i in my_list[j]) {  # Trial loop
   .... 

     }
    }

The background for this is that not all subjects have valid trials. so I need to pass JAGS the valid trials for each subject.

I intended to do that with a nested list like above. However, it turns out JAGS cannot deal with list - so now I try to convert it into something that JAGS can iterate over without losing the information which trials belong to which subject.

I need to keep the structure functioning so everything that just converts the list into a single vector does not help as I cannot iterate over that anymore.

Any suggestions? I have tried to just pass the list, but JAGS cannot deal with that and needs a "double". I also tried to convert it into a matrix, but failed to keep structure.

Thank you!


Update: I tried this, which works somewhat as matrixes seem to work with JAGS

list_as_matrix <- do.call(rbind, my_list)

But the nested lists have different lengths, so the empty columns in the matrix are just filled with the same values over an over again.


The JAGS error code is:

4 nodes produced errors; first error: 'list' object cannot be coerced to type "double"  

Update with the answer thanks to the input from DaveArmstrong:

# a list of 6 subjects and their valid trials
subjects_and_their_valid_trials <- list(
  c(1,3,4,8, 11,13,17), 
  c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20), 
  c(2, 14),
  c(1,3,4,8, 11,13,17), 
  c(1,2,3,4,5,6,8,9,10,11,12,13,14,15,17,18,19,20), 
  c(6, 12))

l <- subjects_and_their_valid_trials # make it easier to read

maxlen <- max(sapply(l, length))
mat <- t(sapply(l, function(x)c(x, rep(NA, maxlen-length(x)))))
minvals <- 1
maxvals <- apply(mat, 1, function(x)max(which(!is.na(x))))


# ---- How the JAGS Loop is structured
nSubj_Condition1 <- 6

# Loop for condition 
for (j in 1:nSubj_Condition1) {  #Subject-loop
  
  print( "///---------------------------------- ///")
  print(paste("Subject number", j))
  
  #-------------------------
  # This loop restricts the following loop to valid cases in the matrix
  for (k in 1:maxvals[j]) { 
    
    print(paste("Iterating through trial matrix... step", k))
    
    # This loop loops through the matrix of valid trials for each subjects 
    for (i in mat[j,k]) {
      
      print(paste("A valid trial number is:", i))
    }
  }
}

Solution

  • What about something like this:

    l <- list(
    c(1,3,4,8, 11,13,17), 
    c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20), 
    c(2, 14))
    

    Turn your list into a matrix that is padded out with NA values.

    maxlen <- max(sapply(l, length))
    mat <- t(sapply(l, function(x)c(x, rep(NA, maxlen-length(x)))))
    
    # > mat
    # [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16]
    # [1,]    1    3    4    8   11   13   17   NA   NA    NA    NA    NA    NA    NA    NA    NA
    # [2,]    1    2    3    4    5    6    7    8    9    10    11    12    13    14    15    16
    # [3,]    2   14   NA   NA   NA   NA   NA   NA   NA    NA    NA    NA    NA    NA    NA    NA
    # [,17] [,18] [,19] [,20]
    # [1,]    NA    NA    NA    NA
    # [2,]    17    18    19    20
    # [3,]    NA    NA    NA    NA
    

    Then, for each subject, identify the first and last columns with valid data.

    minvals <- 1
    maxvals <- apply(mat, 1, function(x)max(which(!is.na(x))))
    

    Then, in your JAGS model, you could pull the appropriate values out of mat to identify the trial numbers.

    for (j in 1:subjects) {  # Subject-loop
      for (i in minvals[j]:maxvals[j]) {  # Trial loop
         mat[j,i] ## gives you the trial number for each subject 
        
      }
    }