rdplyr

How to relocate several columns in one step using dplyr::relocate?


I would like to reorder some columns to come after a particular other column using dplyr::relocate. Here is a MWE:

a <- letters[1:3]
b <- letters[4:6]
c <- letters[7:9]
d <- letters[10:12]

mytib <- tibble::tibble(a,b,c,d)

#  A tibble: 3 x 4
#  a     b     c     d    
#  <chr> <chr> <chr> <chr>
# 1 a     d     g     j    
# 2 b     e     h     k    
# 3 c     f     i     l    

mytib %>%
     relocate(c, .after = a)

This example works but is there a way that I could, with one relocate command, move c after a and, say, d after b?

I tried the following without success:

mytib %>%
     relocate(c(c, d), .after(c(a, b)))

Edit 1: I explicitly ask about relocate because functions like select do not work for large datasets where all I know is after which column (name) I want to insert a column.

Edit 2: This is my expected output:

#  A tibble: 3 x 4
#  a     c     b     d    
#  <chr> <chr> <chr> <chr>
# 1 a     g     d     j    
# 2 b     h     e     k    
# 3 c     i     f     l   

Solution

  • As dplyr::relocate itself apparently doesn't allow relocating in pairs, you can "hack" this behavior by preparing a list of column pairs like the ones you describe ("c after a" & "d after b") and reduce over that list, passing your df in as an .init value and in each reduce-step relocating one pair.

    Like this:

    library(dplyr)
    library(purrr)
    
    df_relocated <- reduce(
      .x = list(c('c','a'), c('d','b')), 
      .f = ~ relocate(.x, .y[1], .after = .y[2]),
      .init = mytib
    )
    

    This produces a tibble just as you expect it:

    > df_relocated
    # A tibble: 3 x 4
      a     c     b     d    
      <chr> <chr> <chr> <chr>
    1 a     g     d     j    
    2 b     h     e     k    
    3 c     i     f     l