Solebay Sharp
Solebay Sharp

Reputation: 533

How to Use 'lapply' on Sublists (r)

I'm trying to use lapply on a list of sublists. However all I can manage is overwriting the sublists with what should be going into them, rather than writing into the sublists.

To make my problem clear to the point of tedium, this would be the same as having a 'Shops List', with 'DIY Store' and 'Gardening Store'. Trying to write 'Hammer and Nails' into the DIY sublist and 'Seeds' into the Gardening sublist, but realising you actually scrawled all your items into 'Shopping List', destroying your sublists.

I imagine there is a simple way to tell R "whoa there, just recursively look at my first layer of sublists". In the hope that this is a simple fix and the wider context isn't overly helpful, my lapply section and where I would think the change should be made, is just below.

# Create a list of Types and the matrices
StatMatrices <- lapply(Types, function(q) {
    # Select Versus List so that for example, a HESH list only contains HESHVersusHEAT<
    # HESHVerusHESH, HESHVersusAPDS and HESHVersusAPDR, and not HEATVersus.. and so on...
    WhichVersus <- grep(paste0("(^", q, ")"), VersusList, value = T, perl = T)
    EmptySublist <- (setNames(vector("list", length(Types)), WhichVersus))
  })
names(StatMatrices) <- Types

Now I have tried a few things like doubling up the lapply, but I'm not even sure I'm doing it correcly, let alone if it's the correct solution.

# Create a list of Types and the matrices
StatMatrices <- lapply(Types,
                       lapply, function(q) {
    # Select Versus List so that for example, a HESH list only contains HESHVersusHEAT<
    # HESHVerusHESH, HESHVersusAPDS and HESHVersusAPDR, and not HEATVersus.. and so on...
    WhichVersus <- grep(paste0("(^", q, ")"), VersusList, value = T, perl = T)
    EmptySublist <- (setNames(vector("list", length(Types)), WhichVersus))
  })
names(StatMatrices) <- Types

My full code is shown below. I've tried to comment it but essentially I have 4 'Types', and I'm creating a lists called StatMatrices. This will contain further lists, the next layer will consist of names such as e.g. VelStatMatrices, names according to the subsequent information that will be stored in them. The next set of lists will be the so called Types (i.e. HEAT,HESH,APDS and APCR). These will contain comparison matrices, though for now are only place holder names. Thus inside HESH you will have HESHVersusHEAT HESHVerusHESH, HESHVersusAPDS and HESHVersusAPDR waiting to be filled with a matrix.

A final list path would look something like this:

StatMatrices[["VelStatMatrices"]][[HESH]][[HESHVerusHEAT]]

and another like this

StatMatrices[["PenStatMatrices"]][["APDS"]][["APDSVerusHESH"]]

Here is what I have so far:

#Mun Types
Types = c("HEAT", "HESH", "APDS", "APCR")

#Create empty vector for Versus name strings
VersusList <- c()

#Create Versus names e.g. HEATVerusAPDS and APCRVersusHESH etc
for (q in 1:length(Types)) {
  for (j in 1:length(Types)) {

    # VersusList(i) <- paste0(Types[q], "Versus", Types[j])
    VersusList <- c(VersusList, paste0(Types[q], "Versus", Types[j]))
  }
}

#Create List of lists of stat matrices, each to be filled with matrices,  
StatMatrices <- list("PenStatMatrices", "DmgStatMatrices", "VelStatMatrices")

# Create a list of Types and the matrices
StatMatrices <- lapply(Types, function(q) {
    # Select Versus List so that for example, a HESH list only contains HESHVersusHEAT<
    # HESHVerusHESH, HESHVersusAPDS and HESHVersusAPDR, and not HEATVersus.. and so on...
    WhichVersus <- grep(paste0("(^", q, ")"), VersusList, value = T, perl = T)
    EmptySublist <- (setNames(vector("list", length(Types)), WhichVersus))
  })
names(StatMatrices) <- Types

I'm only just starting to use lapply and hardly know what I'm doing with R so any help would be appreciated.

Upvotes: 1

Views: 542

Answers (1)

Jozef
Jozef

Reputation: 2737

Sorry for not providing a more concrete answer at this point (maybe a bit more concise question would help) but I would recommend to look at utils::modifyList(). It seems like that could help.

Also, looking at your use case, you may save yourself a bit of pain structuring objects a bit differently, one example is a matrix of matrices:

Make a 4x4 matrix of 4x4 matrices (of random numbers for show):

mtr <- matrix(
  rep(list(matrix(runif(16L), nrow = 4L)), 16L),
  nrow = 4,
  ncol = 4
)

Set the row and col names for better readability

rownames(mtr) <- colnames(mtr) <-  c("HEAT", "HESH", "APDS", "APCR")

And then accessing the data like so:

mtr["HEAT", "HEAT"]

which gives

[[1]]
            [,1]      [,2]      [,3]      [,4]
[1,] 0.413062588 0.2497092 0.6465910 0.9492033
[2,] 0.007168949 0.9049881 0.1491240 0.1494439
[3,] 0.540454187 0.4837212 0.2674728 0.6261278
[4,] 0.327341522 0.9747880 0.7509647 0.5489474

And you have a list of matrices, so you can easily apply functions:

lapply(mtr, summary)

Returning (truncated):

[[1]]
       V1                 V2               V3               V4        
 Min.   :0.007169   Min.   :0.2497   Min.   :0.1491   Min.   :0.1494  
 1st Qu.:0.247298   1st Qu.:0.4252   1st Qu.:0.2379   1st Qu.:0.4491  
 Median :0.370202   Median :0.6944   Median :0.4570   Median :0.5875  
 Mean   :0.322007   Mean   :0.6533   Mean   :0.4535   Mean   :0.5684  
 3rd Qu.:0.444910   3rd Qu.:0.9224   3rd Qu.:0.6727   3rd Qu.:0.7069  
 Max.   :0.540454   Max.   :0.9748   Max.   :0.7510   Max.   :0.9492  

[[2]]
       V1                 V2               V3               V4        
 Min.   :0.007169   Min.   :0.2497   Min.   :0.1491   Min.   :0.1494  
 1st Qu.:0.247298   1st Qu.:0.4252   1st Qu.:0.2379   1st Qu.:0.4491  

...

Upvotes: 1

Related Questions