I have a list of lists. A toy example similar is presented below. I want to extract the rownames from each list,and then store these rownames in either a new data frame or a new list of lists (in the same structure of the original).

Ideally the colnames or new list names would be identical to the list names from the list of lists.

note. the lists are all different lengths and must be taken into account. I would rather not fill the blank spaces with N/A.


dput(head(Chars_alive)):

list(FEB_games = list(GAME1 = structure(list(GAME1_Class = structure(c(2L, 
1L, 5L, 4L, 3L), .Label = c("fighter", "paladin", "rouge", "sorcerer", 
"wizard"), class = "factor"), GAME1_Race = structure(c(3L, 1L, 
4L, 3L, 2L), .Label = c("elf", "gnome", "human", "orc"), class = "factor"), 
GAME1_Alignment = structure(c(4L, 2L, 1L, 5L, 3L), .Label = c("CE", 
"CG", "LG", "NE", "NN"), class = "factor"), GAME1_Level = c(6, 
7, 6, 7, 7), GAME1_Alive = structure(c(1L, 1L, 1L, 1L, 1L
), .Label = "y", class = "factor")), row.names = c("Stan", 
"Kenny", "Cartman", "Kyle", "Butters"), class = "data.frame"), 
GAME2 = structure(list(GAME2_Class = structure(c(5L, 2L, 
4L, 1L), .Label = c("bard", "cleric", "fighter", "monk", 
"wizard"), class = "factor"), GAME2_Race = structure(c(3L, 
2L, 4L, 1L), .Label = c("dwarf", "elf", "half-elf", "human"
), class = "factor"), GAME2_Alignment = structure(c(2L, 1L, 
5L, 3L), .Label = c("CE", "CG", "LG", "NE", "NN"), class = "factor"), 
    GAME2_Level = c(5, 5, 5, 5), GAME2_Alive = structure(c(2L, 
    2L, 2L, 2L), .Label = c("n", "y"), class = "factor")), row.names = c("Kenny", 
"Cartman", "Kyle", "Butters"), class = "data.frame")), MAR_games = list(
GAME3 = structure(list(GAME3_Class = structure(c(2L, 1L, 
5L, 3L), .Label = c("barbarian", "cleric", "monk", "ranger", 
"warlock"), class = "factor"), GAME3_Race = structure(c(2L, 
3L, 2L, 1L), .Label = c("dwarf", "elf", "half-elf", "human"
), class = "factor"), GAME3_Alignment = structure(c(2L, 2L, 
1L, 2L), .Label = c("CE", "LG", "LN"), class = "factor"), 
    GAME3_Level = c(1, 1, 1, 1), GAME3_Alive = structure(c(2L, 
    2L, 2L, 2L), .Label = c("n", "y"), class = "factor")), row.names = c("Stan", 
"Kenny", "Cartman", "Butters"), class = "data.frame"), GAME4 = structure(list(
    GAME4_Class = structure(c(1L, 5L, 4L, 3L), .Label = c("fighter", 
    "paladin", "rouge", "sorcerer", "wizard"), class = "factor"), 
    GAME4_Race = structure(c(3L, 2L, 4L, 1L), .Label = c("dwarf", 
    "elf", "half-elf", "human"), class = "factor"), GAME4_Alignment = structure(c(2L, 
    1L, 4L, 3L), .Label = c("CE", "CG", "LG", "LN"), class = "factor"), 
    GAME4_Level = c(5, 5, 5, 5), GAME4_Alive = structure(c(2L, 
    2L, 2L, 2L), .Label = c("n", "y"), class = "factor")), row.names = c("Kenny", 
"Cartman", "Kyle", "Butters"), class = "data.frame")))

as.data.frame(rownames(Chars_alive[[1]][[1]])) -> GAME1
as.data.frame(rownames(Chars_alive[[2]][[1]])) -> GAME2

Because GAME1 and GAME2 have different lengths a data frame may not be ideal (my actual data has vastly different lengths between lists of lists).

for (i in Chars_alive) {
  for (j in i)
    rownames(j) -> x
}

A for-loop could work but I am new to loops and do not know how to place all the jth elements into one new data frame or list.

ls2 <- list(Game1 <- rownames(Chars_alive[[1]][[1]]), Game2 <- rownames(Chars_alive[[1]][[2]]),
                 Game3 <- rownames(Chars_alive[[2]][[1]]), Game4 <- rownames(Chars_alive[[2]][[2]]))

Perhaps making an new list outright would work, but I'd like to keep the structure of the original list if that was the case i.e. FEB_games > GAME1, GAME2 and MAR_games > GAME3, GAME4. Also I'd prefer to keep the list names the same i.e GAME1, GAME2, GAME3 and GAME4.


Ideal output would be either a data frame:

    GAME1    GAME2    GAME3    GAME4
1   Stan     Kenny    Stan     Kenny
2   Kenny    Cartman  Kenny    Cartman
3   Cartman  Kyle     Cartman  Kyle 
4   Kyle     Butters  Butters  Butters
5   Butters   

Or a list:

Listname
    FEB_games
        GAME1
           'Stan', 'Kenny', 'Cartman', 'Kyle', 'Butters'
        GAME2
           'Kenny', 'Cartman', 'Kyle', 'Butters'
    MAR_games
        GAME3
            'Stan', 'Kenny', 'Cartman', 'Butters'
        GAME4
            'Kenny', 'Cartman', 'Kyle', 'Butters'

score:3

Accepted answer

Hello I would use lapply in lapply like this. I call your list "list_games".

lapply(list_games, function(x){lapply(x, row.names)})

This gives you

$FEB_games
$FEB_games$GAME1
[1] "Stan"    "Kenny"   "Cartman" "Kyle"    "Butters"

$FEB_games$GAME2
[1] "Kenny"   "Cartman" "Kyle"    "Butters"


$MAR_games
$MAR_games$GAME3
[1] "Stan"    "Kenny"   "Cartman" "Butters"

$MAR_games$GAME4
[1] "Kenny"   "Cartman" "Kyle"    "Butters"

If the rownames where of same length, you could save it as a data.frame with

do.call("rbind.data.frame", lapply(list_games, function(x){lapply(x, row.names)}))

This doesn't work here since there length of the rownames is not the same length. In this case you can do something like this:

res <- sapply(list_games, function(x){lapply(x, row.names)})
n.obs <- sapply(res , length)
seq.max <- seq_len(max(n.obs))
df <- data.frame(t(sapply(res, "[", i = seq.max)))
df
     X1      X2      X3      X4      X5
1  Stan   Kenny Cartman    Kyle Butters
2 Kenny Cartman    Kyle Butters    <NA>
3  Stan   Kenny Cartman Butters    <NA>
4 Kenny Cartman    Kyle Butters    <NA>

If you need further explanation let me know. The last part was done like here