dplyr select column based on string match

Viewed 435

I am wanting to order my columns of a data frame by string matches.

library(dplyr)
data <- data.frame(start_a = 1,
           start_f = 3,
           end_a = 5,
           end_f = 7,
           middle_a= 9,
           middle_f = 11) 
  • For example I want to select start_f, start_a, middle_f, middle_a, end_f ,end_a
  • I am attempting to do so with data %>% select(matches("(start|middle|end)_(f|a)"))), so that the order I have typed within the matches is the order that I want the columns to be selected.
  • Desired output would be data[c(2,1,6,5,4,3)]
1 Answers

You can construct the columns in the order that you want with outer.

order1 <- c('start', 'middle', 'end')
order2 <- c('f', 'a')
cols <- c(t(outer(order1, order2, paste, sep = '_')))
cols
#[1] "start_f"  "start_a"  "middle_f" "middle_a" "end_f"    "end_a" 

data[cols]
#  start_f start_a middle_f middle_a end_f end_a
#1       3       1       11        9     7     5

If not all combinations of order1 and order2 are present in the data we can use any_of which will select only the columns present in data without giving any error.

library(dplyr)
data %>% select(any_of(cols))

To select based on pattern in names.

order1 <- c('start', 'middle', 'end')
order2 <- c('f', 'a')
pattern <- c(t(outer(order1, order2, function(x, y) sprintf('^%s_%s.*', x, y))))
pattern
#[1] "^start_f.*"  "^start_a.*"  "^middle_f.*" "^middle_a.*" "^end_f.*" "^end_a.*" 
cols <- names(data)

data[sapply(pattern, function(x) grep(x, cols))]

#  start_f start_a middle_f middle_a end_f end_a
#1       3       1       11        9     7     5
Related