63

Given data:

library(data.table)
DT = data.table(category=LETTERS[1:3], b=1:3)
DT
#    category b
# 1:        A 1
# 2:        B 2
# 3:        C 3

Using dplyr, how to rearrange rows to get specific order c("C", "A", "B") in category?

#    category b
# 1:        C 3
# 2:        A 1
# 3:        B 2
zx8754
  • 52,746
  • 12
  • 114
  • 209
Daniel Krizian
  • 4,586
  • 4
  • 38
  • 75

2 Answers2

111

First, create a vector with the letters in the desired order. Then match* the vector with the variable to be sorted. match returns indices of (first) matches, which can be plugged into slice:

library(dplyr)

# create a vector with letters in the desired order
x <- c("C", "A", "B")

DT %>%
  slice(match(x, category))
#   category b
# 1        C 3
# 2        A 1
# 3        B 2

Another way would be to convert "category" to a factor, set levels to the desired order, and use arrange:

DT %>%
  mutate(category =  factor(category, levels = x)) %>%
  arrange(category)    
#   category b
# 1        C 3
# 2        A 1
# 3        B 2

*The match method is inspired by this answer.

Community
  • 1
  • 1
Henrik
  • 65,555
  • 14
  • 143
  • 159
  • 4
    As mentioned in the inspiring answer, watch out for the effect of duplicates when using `match()`. – farnsy Oct 24 '14 at 16:28
5

An alternative could be the following, note that arrange can take a list of new indices.

library(dplyr)

df <- data.frame(category = LETTERS[1:3], b = 1:3, stringsAsFactors = F)

# create a vector with letters in the desired order
x <- c("C", "A", "B")

df %>%
arrange(sapply(category, function(y) which(y == x))
Viktor Horváth
  • 139
  • 2
  • 3