Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extract all values from list of lists with same vector name

Tags:

r

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.

like image 287
Deset Avatar asked Oct 18 '15 21:10

Deset


2 Answers

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
like image 149
josliber Avatar answered Oct 02 '22 11:10

josliber


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
like image 32
David Arenburg Avatar answered Oct 02 '22 12:10

David Arenburg