Another option, dplyr
/base only. This relies on the assumption that there is only one such "number" within each value, and it is not interrupted. (For instance, "A1B2C"
will sort here as 12
.)
dat %>%
arrange(suppressWarnings(as.integer(gsub("\\D", "", ID))))
# ID
# 1 Q1
# 2 Q2
# 3 Q3
# 4 Q4
# 5 Q10
If you prefer to only use the first (if multiple) number, then we can use readr::parse_number
:
dat %>%
arrange(suppressWarnings(readr::parse_number(ID)))
# ID
# 1 Q1
# 2 Q2
# 3 Q3
# 4 Q4
# 5 Q10
I continue to suppressWarnings
because any field with no numbers will be noisy, as in
readr::parse_number("Q")
# Warning: 1 parsing failure.
# row col expected actual
# 1 -- a number Q
# [1] NA
# attr(,"problems")
# # A tibble: 1 x 4
# row col expected actual
# <int> <int> <chr> <chr>
# 1 1 NA a number Q
For the sake of this example, we don't care about the "problems"
attribute attached to the output, and having it as NA
is acceptable.
Data
dat <- structure(list(ID = c("Q2", "Q3", "Q4", "Q10", "Q1")), row.names = c(2L, 3L, 4L, 5L, 1L), class = "data.frame")