Deset
Deset

Reputation: 947

Extract all values from list of lists with same vector name

I have the following list of lists:

list_1 <- list(a = 2, b = 3)
list_2 <- list(a=c(5,6), b= c(2,3))
list_3 <- list(a=c(10,5,8,1), b=c(9,6,2,9))
list_4 <- list(a=c(2,5,58), b=c(69,6,23))
mylist <- list(list_1, list_2, list_3, list_4)
names(mylist)<- c("list_1", "list_2", "list_3", "list_4")

Now what I want is to extract all the a and b values from the lists and save them either as a data.frame with the corresponding list names as a ID column like:

    [ID]      [a]   [b]
[1] list_1    2     3
[2] list_2    5     2
[3] list_2    6     3
[4] list_3    10    9              
[5] list_3    5     6
[6] list_3    8     2
[7] list_3    1     9    
[8] list_4    2     69
[9] list_4    5     6
[10] list_4   58    23

or as variables, such that a contains all a values, b contains all b values, and ID contains the corresponding list IDs:

[a]
2 5 6 10 5 8 1 2 5 58
[b]
3 2 3 9 6 2 9 69 6 23
[ID]
"list_1" "list_2" "list_2" "list_3" "list_3" "list_3" "list_3" "list_4" "list_4" "list_4"

I tried the second approach with a for loop but couldn't mange to archive the desired result. But even if I could manage that I don't know how I would solve the ID thing. It would be great if the solution could be a general one, because I have many such lists of different lengths.

Upvotes: 7

Views: 2752

Answers (3)

jazzurro
jazzurro

Reputation: 23574

This is a bit of extra. I think the purrr package offers something pretty good in this case. The following returns a list that is similar to one by David Arenburg. The difference is that the ID part stays as names in each vector.

library(purrr)
mylist %>% zip_n(.simplify = TRUE)

#$a
# list_1 list_21 list_22 list_31 list_32 list_33 list_34 list_41 
#      2       5       6      10       5       8       1       2 
#list_42 list_43 
#      5      58 
#
#$b
# list_1 list_21 list_22 list_31 list_32 list_33 list_34 list_41 
#      3       2       3       9       6       2       9      69 
#list_42 list_43 
#      6      23 

Upvotes: 1

David Arenburg
David Arenburg

Reputation: 92282

I would just rbind the lists and add the row names as ID. This way you don't need to worry about the column names at all. Or you can just leave the row.names as the ID and just settle with do.call(rbind.data.frame, mylist)

res <- do.call(rbind.data.frame, mylist)
res$ID <- sub("\\..*", "", row.names(res))
row.names(res) <- NULL
res
#     a  b     ID
# 1   2  3 list_1
# 2   5  2 list_2
# 3   6  3 list_2
# 4  10  9 list_3
# 5   5  6 list_3
# 6   8  2 list_3
# 7   1  9 list_3
# 8   2 69 list_4
# 9   5  6 list_4
# 10 58 23 list_4

Alternately you could also do

res <- do.call(rbind.data.frame, mylist)
as.list(cbind(res, ID = row.names(res)))
# $a
# [1]  2  5  6 10  5  8  1  2  5 58
# 
# $b
# [1]  3  2  3  9  6  2  9 69  6 23
# 
# $ID
# [1] list_1    list_2.2  list_2.3  list_3.4  list_3.5  list_3.6  list_3.7  list_4.8  list_4.9  list_4.10
# Levels: list_1 list_2.2 list_2.3 list_3.4 list_3.5 list_3.6 list_3.7 list_4.10 list_4.8 list_4.9

Upvotes: 3

josliber
josliber

Reputation: 44299

In base R, you could loop through the names of mylist, for each name generating a data frame with that name as the ID variable and all variables from the relevant element of mylist. Then you could combine all the generated data frames together with do.call and rbind:

do.call(rbind, lapply(names(mylist), function(x) data.frame(c(ID=x, mylist[[x]]))))
#        ID  a  b
# 1  list_1  2  3
# 2  list_2  5  2
# 3  list_2  6  3
# 4  list_3 10  9
# 5  list_3  5  6
# 6  list_3  8  2
# 7  list_3  1  9
# 8  list_4  2 69
# 9  list_4  5  6
# 10 list_4 58 23

Upvotes: 3

Related Questions