0

I'm attempting to flatten a vector that contains a number of lists. What would be the best way to do that while retaining the data associated with that list? I tried using unlist but that gave me a list that was unconnected to my data.

## My data set looks something like this:
df <- data.frame(A = c(1,2,3),
                 B = c(3,5,4),
                 C = c(4,3,5),
                 D = c(7,9,2))
df$E <- list(c(5, 3, 2, 1), 5, c(5, 2, 1))
df
##  A B C D          E
## 1 1 3 4 7 5, 3, 2, 1
## 2 2 5 3 9          5
## 3 3 4 5 2    5, 2, 1

## Ideally I would like it to look like this:
 A B C D E
1 1 3 4 7 5 
2 1 3 4 7 3
3 1 3 4 7 2
4 1 3 4 7 1
5 2 5 3 9 5
6 3 4 5 2 5,
7 3 4 5 2 5 
8 3 4 5 2 2
9 3 4 5 2 1

Is there a simple way to do that?

Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
  • 2
    `tidyr::unnest` – Rich Scriven Dec 06 '16 at 19:50
  • Especially with questions like this, you'll want to give a reproducible example, not just a representation of what the object looks like. Some guidance: http://stackoverflow.com/a/28481250/ – Frank Dec 06 '16 at 19:53
  • In base R: `data.frame(df[rep(1:nrow(df), lengths(df$E)), 1:4], E = unlist(df$E), row.names = NULL)` – Jaap Dec 06 '16 at 20:54
  • This isn't a duplicate of the question it is listed as a duplicate of. Please reopen it or select an actual duplicate question. – Ista Dec 06 '16 at 21:55

2 Answers2

2

Very simple. Let's say your data frame is called df.

library(tidyr)
df %>% unnest(E)

Data:

structure(list(A = 1:3, B = c(3L, 5L, 4L), C = c(4L, 3L, 5L), 
D = c(7L, 9L, 2L), E = list(c(5, 3, 2, 1), 5, c(5, 2, 1))), .Names = c("A", 
"B", "C", "D", "E"), row.names = c(NA, -3L), class = "data.frame")
Joe
  • 8,073
  • 1
  • 52
  • 58
1

Probably not the shortest way to go about it but this will get the results you want without relying on an extra library.

First to define the data set itself,as you have described

testdata<-t(matrix(list(1,3,4,7,c(5,3,2,1),
                      2,5,3,9,5,
                      3,4,5,2,c(5,2,1)
                      ),nrow=5))

colnames(testdata)<-c("A","B","C","D","E")

rownames(testdata)<-c(1,2,3)

testdata is as follows, where Numeric,4 is c(5,3,2,1) and Numeric,3 is c(5,2,1)

  A B C D E        
1 1 3 4 7 Numeric,4
2 2 5 3 9 5        
3 3 4 5 2 Numeric,3

the expandall function is superfluous but it helps to break up the code into more readable chunks.

expandall<-function(x){
    do.call(cbind,x)
}

result<-apply(testdata,1,expandall)
if(is.list(result)){ ## if there are sub arrays then apply will return 
                     ## a list
    result<-do.call(rbind,result)
}

applying expandall to each row of the data and binding the results we get

     A B C D E
[1,] 1 3 4 7 5
[2,] 1 3 4 7 3
[3,] 1 3 4 7 2
[4,] 1 3 4 7 1
[5,] 2 5 3 9 5
[6,] 3 4 5 2 5
[7,] 3 4 5 2 2
[8,] 3 4 5 2 1