Search code examples
rselectdplyrtidyselect

Using everything() from tidyselect in dplyr to select a variable last


I would like to programmatically tell what column I'd like to display LAST. The function everything() from tidyr is great when it is used as the last argument --you specify everything before it and let it do the rest

But what if I want to do it the other way-- say what variable I want last, and then have everything() (or another function) provide all variables not selected before it.

Suppose in the example below I'd like to select cyl as the last variable to display...

library(tidyverse)

data = mtcars %>% as_tibble() %>% select(1:4)

data %>% select( cyl,everything()) #works -- cyl at beginning
#> # A tibble: 32 × 4
#>      cyl   mpg  disp    hp
#>    <dbl> <dbl> <dbl> <dbl>
#>  1     6  21    160    110
#>  2     6  21    160    110
#>  3     4  22.8  108     93
#>  4     6  21.4  258    110
#>  5     8  18.7  360    175
#>  6     6  18.1  225    105
#>  7     8  14.3  360    245
#>  8     4  24.4  147.    62
#>  9     4  22.8  141.    95
#> 10     6  19.2  168.   123
#> # … with 22 more rows

data %>% select(everything(), cyl) #does not work! -- cyl not at end!
#> # A tibble: 32 × 4
#>      mpg   cyl  disp    hp
#>    <dbl> <dbl> <dbl> <dbl>
#>  1  21       6  160    110
#>  2  21       6  160    110
#>  3  22.8     4  108     93
#>  4  21.4     6  258    110
#>  5  18.7     8  360    175
#>  6  18.1     6  225    105
#>  7  14.3     8  360    245
#>  8  24.4     4  147.    62
#>  9  22.8     4  141.    95
#> 10  19.2     6  168.   123
#> # … with 22 more rows

Created on 2022-07-19 by the reprex package (v2.0.1)

I would want it to look like this


data %>% some_fxn() 
# A tibble: 32 × 4
     mpg  disp    hp   cyl
   <dbl> <dbl> <dbl> <dbl>
 1  21    160    110     6
 2  21    160    110     6
 3  22.8  108     93     4
 4  21.4  258    110     6
 5  18.7  360    175     8
 6  18.1  225    105     6
 7  14.3  360    245     8
 8  24.4  147.    62     4
 9  22.8  141.    95     4
10  19.2  168.   123     6
# … with 22 more rows

Is there another function or an option to everything() to allow it to do this?


Solution

  • You can use the relocate() verb

    data %>% 
      relocate(cyl, .after = last_col())
    

    If you are going to often move things to the end of the data.frame, you can write your own helper

    relocate_end <- function(..., .after=NULL) {
      relocate(..., .after=last_col())
    }
    

    and this will work with multiple columns as well

    data %>% relocate_end(cyl, mpg)
    #    disp    hp   cyl   mpg
    #    <dbl> <dbl> <dbl> <dbl>
    #  1  160    110     6  21  
    #  2  160    110     6  21  
    #  3  108     93     4  22.8
    #  4  258    110     6  21.4
    #  5  360    175     8  18.7
    #  6  225    105     6  18.1
    #  7  360    245     8  14.3
    #  8  147.    62     4  24.4
    #  9  141.    95     4  22.8
    # 10  168.   123     6  19.2