How to turn a list into a datataframe with a column that identifies each subelement of a list in R?

Viewed 43

Let's say I have the following list which I want to turn into a dataframe:

list1 = list(c("Text1","text2","text3","text4"),c("Text 1","text2","text3"),c("Text 3","text2"), c("Text 4"))

[[1]]
[1] "Text1" "text2" "text3" "text4"

[[2]]
[1] "Text 1" "text2"  "text3" 

[[3]]
[1] "Text 3" "text2" 

[[4]]
[1] "Text 4"

To turn a list into a dataframe, I do this:

data.frame(Text = matrix(unlist(list1)), stringsAsFactors = F)

    Text
1   Text1
2   text2
3   text3
4   text4
5  Text 1
6   text2
7   text3
8  Text 3
9   text2
10 Text 4

However, I lost track of which element belonged to which list. I would rather need the following output:


    ID    Text
1   1.1      Text1
2   1.2      text2
3   1.3      text3
4   1.4      text4
5   2.1      Text 1
6   2.2      text2
7   2.3      text3
8   3.1      Text 3
9   3.2      text2
10  4.1      Text 4

I'm stuck here unable to add another ID column where the first number indicates the number of the list and the second number denotes the sublist element in the nth list.

Can anyone help me with this?

Thanks!

4 Answers

Use enframe and unnest

library(tidyverse)
enframe(list1, name = "ID", value = "text") %>% 
  unnest(text)
# A tibble: 10 × 2
      ID text  
   <int> <chr> 
 1     1 Text1 
 2     1 text2 
 3     1 text3 
 4     1 text4 
 5     2 Text 1
 6     2 text2 
 7     2 text3 
 8     3 Text 3
 9     3 text2 
10     4 Text 4

I would do it this way:

data.frame(ID=paste0(rep(seq_along(list1), sapply(list1, length)),
                     '.',
                     unlist(sapply(list1, seq_along))),
           Text=unlist(list1))
#     ID   Text
# 1  1.1  Text1
# 2  1.2  text2
# 3  1.3  text3
# 4  1.4  text4
# 5  2.1 Text 1
# 6  2.2  text2
# 7  2.3  text3
# 8  3.1 Text 3
# 9  3.2  text2
# 10 4.1 Text 4

Another way to generate the IDs:

unlist(mapply(paste, 
              seq_along(list1), 
              sapply(list1, seq_along), 
              sep='.'))

Assign names to the list and stack():

stack(setNames(list1, seq_along(list1)))

   values ind
1   Text1   1
2   text2   1
3   text3   1
4   text4   1
5  Text 1   2
6   text2   2
7   text3   2
8  Text 3   3
9   text2   3
10 Text 4   4

Another way in the tidyverse. This gives you two IDs for the list element and then vector element.

library(purrr)
library(tibble)

map_dfr(list1, enframe, name = "ID2", value = "text", .id = "ID")
# A tibble: 10 x 3
   ID      ID2 text  
   <chr> <int> <chr> 
 1 1         1 Text1 
 2 1         2 text2 
 3 1         3 text3 
 4 1         4 text4 
 5 2         1 Text 1
 6 2         2 text2 
 7 2         3 text3 
 8 3         1 Text 3
 9 3         2 text2 
10 4         1 Text 4
Related