Reputation: 1848
Let I have the below list(list2) where the elements of the list is also a list:
> dput(list2)
list(x = list(a = c(0.18, 0.7, 0.57, 0.17, 0.94), b = c(0.18,
0.7, 0.57, 0.17, 0.94)), y = list(a = c(0.18, 0.7, 0.57, 0.17,
0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)), z = list(a = c(0.18,
0.7, 0.57, 0.17, 0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)))
where I generated the list as below:
names1<-c("a","b")
names2<-c("x","y","z")
list1<-list()
list2<-list()
for(i in names1)
for(j in names2){{
set.seed(2)
list1[[i]]<-round(runif(5),2)
list2[[j]]<-list1
}}
I want to reshape this list as below data frame:
n1 n2 n3
1 x a 0.18
2 x a 0.70
3 x a 0.57
4 x a 0.17
5 x a 0.94
6 x b 0.18
7 x b 0.70
8 x b 0.57
9 x b 0.17
10 x b 0.94
11 y a 0.18
12 y a 0.70
13 y a 0.57
14 y a 0.17
15 y a 0.94
16 y b 0.18
17 y b 0.70
18 y b 0.57
19 y b 0.17
20 y b 0.94
21 z a 0.18
22 z a 0.70
23 z a 0.57
24 z a 0.17
25 z a 0.94
26 z b 0.18
27 z b 0.70
28 z b 0.57
29 z b 0.17
30 z b 0.94
How caı I reshape the list? My original list is much bigger than the above example.
Thanks a lot.
Upvotes: 1
Views: 181
Reputation: 101343
A base R option
setNames(
`row.names<-`(rev(
do.call(
rbind,
Map(cbind,
Map(stack, list2),
n = names(list2)
)
)
), NULL),
paste0("n", 1:3)
)
gives
n1 n2 n3
1 x a 0.18
2 x a 0.70
3 x a 0.57
4 x a 0.17
5 x a 0.94
6 x b 0.18
7 x b 0.70
8 x b 0.57
9 x b 0.17
10 x b 0.94
11 y a 0.18
12 y a 0.70
13 y a 0.57
14 y a 0.17
15 y a 0.94
16 y b 0.18
17 y b 0.70
18 y b 0.57
19 y b 0.17
20 y b 0.94
21 z a 0.18
22 z a 0.70
23 z a 0.57
24 z a 0.17
25 z a 0.94
26 z b 0.18
27 z b 0.70
28 z b 0.57
29 z b 0.17
30 z b 0.94
Upvotes: 2
Reputation: 1202
Why don't you create directly the dataframe?
names1<-c("a","b")
names2<-c("x","y","z")
b= matrix(ncol=3)[-1,]
for(i in names1)
for(j in names2){{
a<-as.data.frame(round(runif(5),2))
a$n1 = j
a$n2 = i
b = rbind(b,a)
}}
b = b[,c(2,3,1)]
colnames(b)[3]='n3'
the result looks like this:
n1 n2 n3
1 x a 0.85
2 x a 0.98
3 x a 0.23
4 x a 0.44
5 x a 0.07
6 y a 0.66
7 y a 0.39
8 y a 0.84
9 y a 0.15
10 y a 0.35
11 z a 0.49
12 z a 0.15
13 z a 0.36
14 z a 0.96
15 z a 0.13
16 x b 0.01
17 x b 0.16
18 x b 0.81
19 x b 0.87
20 x b 0.51
21 y b 0.63
22 y b 0.84
23 y b 0.28
24 y b 0.67
25 y b 0.15
26 z b 0.98
27 z b 0.30
28 z b 0.12
29 z b 0.16
30 z b 0.94
Upvotes: 0
Reputation: 388982
You can use stack
with lapply
and combine the data with bind_rows
-
dplyr::bind_rows(lapply(list2, stack), .id = 'n1')
# n1 values ind
#1 x 0.18 a
#2 x 0.70 a
#3 x 0.57 a
#4 x 0.17 a
#5 x 0.94 a
#6 x 0.18 b
#7 x 0.70 b
#8 x 0.57 b
#9 x 0.17 b
#10 x 0.94 b
#11 y 0.18 a
#12 y 0.70 a
#13 y 0.57 a
#14 y 0.17 a
#15 y 0.94 a
#16 y 0.18 b
#17 y 0.70 b
#18 y 0.57 b
#19 y 0.17 b
#20 y 0.94 b
#21 z 0.18 a
#22 z 0.70 a
#23 z 0.57 a
#24 z 0.17 a
#25 z 0.94 a
#26 z 0.18 b
#27 z 0.70 b
#28 z 0.57 b
#29 z 0.17 b
#30 z 0.94 b
If you want to keep this in base R :
data <- lapply(list2, stack)
do.call(rbind, Map(cbind, data, n1 = names(data)))
Upvotes: 2
Reputation: 26218
purrr::imap_dfr
based solution
list2 <- list(x = list(a = c(0.18, 0.7, 0.57, 0.17, 0.94), b = c(0.18,
0.7, 0.57, 0.17, 0.94)), y = list(a = c(0.18, 0.7, 0.57, 0.17,
0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)), z = list(a = c(0.18,
0.7, 0.57, 0.17, 0.94), b = c(0.18, 0.7, 0.57, 0.17, 0.94)))
library(tidyverse)
imap_dfr(list2, ~.x %>% as.data.frame() %>%
mutate(n1 = .y) %>%
pivot_longer(!n1, names_to = 'n2', values_to = 'n3'))
#> # A tibble: 30 x 3
#> n1 n2 n3
#> <chr> <chr> <dbl>
#> 1 x a 0.18
#> 2 x b 0.18
#> 3 x a 0.7
#> 4 x b 0.7
#> 5 x a 0.57
#> 6 x b 0.57
#> 7 x a 0.17
#> 8 x b 0.17
#> 9 x a 0.94
#> 10 x b 0.94
#> # ... with 20 more rows
Created on 2021-05-26 by the reprex package (v2.0.0)
Upvotes: 2