This post seems relevant/similar but not quite the same issue: `dplyr::bind_rows` not working while combining listed tibbles
I'm trying to bind the rows of multiple tibbles in 2 named lists. I've been using imap to iterate across list elements because it retains the names (map doesn't it seems). However, bind_rows doesn't seem to work here for some reason. It creates weird column names. It only seems to work with an unnamed list, but then I lose the names.
library(tidyverse)
# named lists
list1 <- list(
tibble(a = 1:4, b = LETTERS[1:4]),
tibble(a = 5:8, b = LETTERS[5:8]),
tibble(a = 9:12, b = LETTERS[9:12])
) %>% set_names(c("X","Y","Z"))
list2 <- list(
tibble(a = 3:6, b = LETTERS[3:6], c = 3:6 / 2),
tibble(a = 7:10, b = LETTERS[7:10], c = 7:10 / 2),
tibble(a = 11:14, b = LETTERS[11:14], c = 11:14 / 2)
) %>% set_names(c("X","Y","Z"))
# subsetting a named lists with bind_rows creates weird column names
list1 %>% imap(~ {
.x %>% bind_rows(list2[.y])
})
#> $X
#> # A tibble: 8 × 3
#> a b X$a $b $c
#> <int> <chr> <int> <chr> <dbl>
#> 1 1 A NA NA NA
#> 2 2 B NA NA NA
#> 3 3 C NA NA NA
#> 4 4 D NA NA NA
#> 5 NA NA 3 C 1.5
#> 6 NA NA 4 D 2
#> 7 NA NA 5 E 2.5
#> 8 NA NA 6 F 3
#>
#> $Y
#> # A tibble: 8 × 3
#> a b Y$a $b $c
#> <int> <chr> <int> <chr> <dbl>
#> 1 5 E NA NA NA
#> 2 6 F NA NA NA
#> 3 7 G NA NA NA
#> 4 8 H NA NA NA
#> 5 NA NA 7 G 3.5
#> 6 NA NA 8 H 4
#> 7 NA NA 9 I 4.5
#> 8 NA NA 10 J 5
#>
#> $Z
#> # A tibble: 8 × 3
#> a b Z$a $b $c
#> <int> <chr> <int> <chr> <dbl>
#> 1 9 I NA NA NA
#> 2 10 J NA NA NA
#> 3 11 K NA NA NA
#> 4 12 L NA NA NA
#> 5 NA NA 11 K 5.5
#> 6 NA NA 12 L 6
#> 7 NA NA 13 M 6.5
#> 8 NA NA 14 N 7
# subsetting unnamed lists works but loses names
list1 -> list1 %>% unname()
list2 -> list2 %>% unname()
list1 %>% imap(~ {
.x %>% bind_rows(list2[.y])
})
#> [[1]]
#> # A tibble: 8 × 3
#> a b c
#> <int> <chr> <dbl>
#> 1 1 A NA
#> 2 2 B NA
#> 3 3 C NA
#> 4 4 D NA
#> 5 3 C 1.5
#> 6 4 D 2
#> 7 5 E 2.5
#> 8 6 F 3
#>
#> [[2]]
#> # A tibble: 8 × 3
#> a b c
#> <int> <chr> <dbl>
#> 1 5 E NA
#> 2 6 F NA
#> 3 7 G NA
#> 4 8 H NA
#> 5 7 G 3.5
#> 6 8 H 4
#> 7 9 I 4.5
#> 8 10 J 5
#>
#> [[3]]
#> # A tibble: 8 × 3
#> a b c
#> <int> <chr> <dbl>
#> 1 9 I NA
#> 2 10 J NA
#> 3 11 K NA
#> 4 12 L NA
#> 5 11 K 5.5
#> 6 12 L 6
#> 7 13 M 6.5
#> 8 14 N 7
CodePudding user response:
You should use double brackets [[
to extract the element of a list. What you subset by a single bracket [
from a list is still a list. You could check the difference between list2["X"]
and list2[["X"]]
.
list1 %>% imap(~ {
.x %>% bind_rows(list2[[.y]])
})
Output
$X
# A tibble: 8 × 3
a b c
<int> <chr> <dbl>
1 1 A NA
2 2 B NA
3 3 C NA
4 4 D NA
5 3 C 1.5
6 4 D 2
7 5 E 2.5
8 6 F 3
$Y
# A tibble: 8 × 3
a b c
<int> <chr> <dbl>
1 5 E NA
2 6 F NA
3 7 G NA
4 8 H NA
5 7 G 3.5
6 8 H 4
7 9 I 4.5
8 10 J 5
$Z
# A tibble: 8 × 3
a b c
<int> <chr> <dbl>
1 9 I NA
2 10 J NA
3 11 K NA
4 12 L NA
5 11 K 5.5
6 12 L 6
7 13 M 6.5
8 14 N 7
CodePudding user response:
Another possible solution, based on purrr::map2
:
library(tidyverse)
map2(list1, list2, bind_rows)
#> $X
#> # A tibble: 8 x 3
#> a b c
#> <int> <chr> <dbl>
#> 1 1 A NA
#> 2 2 B NA
#> 3 3 C NA
#> 4 4 D NA
#> 5 3 C 1.5
#> 6 4 D 2
#> 7 5 E 2.5
#> 8 6 F 3
#>
#> $Y
#> # A tibble: 8 x 3
#> a b c
#> <int> <chr> <dbl>
#> 1 5 E NA
#> 2 6 F NA
#> 3 7 G NA
#> 4 8 H NA
#> 5 7 G 3.5
#> 6 8 H 4
#> 7 9 I 4.5
#> 8 10 J 5
#>
#> $Z
#> # A tibble: 8 x 3
#> a b c
#> <int> <chr> <dbl>
#> 1 9 I NA
#> 2 10 J NA
#> 3 11 K NA
#> 4 12 L NA
#> 5 11 K 5.5
#> 6 12 L 6
#> 7 13 M 6.5
#> 8 14 N 7