rlisttibble

Combining (binding columns of) tibbles with identical names by name in a named list in R?


I have a named list containing tibbles as elements. I would like to bind_cols of those tibbles whose names are the same within that list. For example:

list(A = tibble(alpha = 1:5, beta = 2:6), B = tibble(delta = 1:8), A = tibble(gamma = 3:7))

> list(A = tibble(alpha = 1:5, beta = 2:6), B = tibble(delta = 1:8), A = tibble(gamma = 3:7))
$A
# A tibble: 5 × 2
  alpha  beta
  <int> <int>
1     1     2
2     2     3
3     3     4
4     4     5
5     5     6

$B
# A tibble: 8 × 1
  delta
  <int>
1     1
2     2
3     3
4     4
5     5
6     6
7     7
8     8

$A
# A tibble: 5 × 1
  gamma
  <int>
1     3
2     4
3     5
4     6
5     7


I would like to transform this into, i.e. this is my desired output:

list(A = tibble(alpha = 1:5, beta = 2:6, gamma = 3:7), B = tibble(delta = 1:8))

$A
# A tibble: 5 × 3
  alpha  beta gamma
  <int> <int> <int>
1     1     2     3
2     2     3     4
3     3     4     5
4     4     5     6
5     5     6     7

$B
# A tibble: 8 × 1
  delta
  <int>
1     1
2     2
3     3
4     4
5     5
6     6
7     7
8     8

How this could be achieved?


Solution

  • We can split on the names of L, then use bind_cols:

    library(dplyr)
    split(L, names(L)) |>
      lapply(bind_cols)
    # $A
    # # A tibble: 5 × 3
    #   alpha  beta gamma
    #   <int> <int> <int>
    # 1     1     2     3
    # 2     2     3     4
    # 3     3     4     5
    # 4     4     5     6
    # 5     5     6     7
    # $B
    # # A tibble: 8 × 1
    #   delta
    #   <int>
    # 1     1
    # 2     2
    # 3     3
    # 4     4
    # 5     5
    # 6     6
    # 7     7
    # 8     8
    

    Note: in this case, bind_cols works well because they have the same number of rows. If the row-counts are different or if there is another condition on which they should be combined (aka "merged" or "joined"), then you will need another function such as *_join or merge.

    Also, I inferred dplyr from your use of tibble(..), though this can be done with base R as well:

    split(L, names(L)) |>
      lapply(\(x) do.call(cbind, unname(x)))