How to sort a character vector where elements contain letters and numbers in R?
RSortingR FaqR Problem Overview
I have a character array
cf <- c("V440","V457","V116","V327","V446","V108",
"V155","V217","V120","V51","V477")
I would like to sort it in descending order so that I will have an output like this:
V51
V108
V116
V120
V155
V217
V327
V440
V446
V457
V477
I have tried sort.list()
like this
cf[sort.list(cf)]
and got this answer:
[1] "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477" "V51"
and also tried order()
and got same result.
Can someone help me please
R Solutions
Solution 1 - R
Try mixedsort
from the "gtools" package:
> # install.packages("gtools") ## Uncomment if not already installed
> library(gtools)
> mixedsort(cf)
[1] "V51" "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
If you don't want to use mixedsort
(not sure why one wouldn't), and if your vector has a pretty consistent pattern (eg letters followed by numbers), you can also probably try something like this. (Note: Relatively untested.)
newvec <- c("V440", "V457", "V116", "V327", "V446", "V108", "V155",
"V217", "V120", "V51", "V477", "B22", "A10", "Z01")
newvec[order(gsub("([A-Z]+)([0-9]+)", "\\1", newvec),
as.numeric(gsub("([A-Z]+)([0-9]+)", "\\2", newvec)))]
# [1] "A10" "B22" "V51" "V108" "V116" "V120" "V155" "V217" "V327" "V440"
# [11] "V446" "V457" "V477" "Z01"
Solution 2 - R
Plenty of right answers here, this is another way, just for fun.
cf[order(nchar(cf), cf)]
# [1] "V51" "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
Solution 3 - R
One more solution in a line of code using str_sort
function (from the stringr
packg.)
# install.packages("stringr") ## Uncomment if not already installed
library(stringr)
str_sort(cf, numeric = TRUE)
[1] "V51" "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446" "V457" "V477"
Solution 4 - R
Just scrape off the preceding "V" character to build a sorting vector. No additional fancy tools required.
vals <- as.numeric(gsub("V","", cf))
cf[order(vals)]
[1] "V51" "V108" "V116" "V120" "V155" "V217" "V327" "V440" "V446"
[10] "V457" "V477"
Solution 5 - R
R correctly orders strings alphabetically, that is why you get that result.
Aside from @Ananda very good answer, if you want to use base R you can use strsplit
to remove the "V" from each string and then use as.numeric
to cast the strings to integers:
vals <- as.numeric(sapply(cf, FUN=function(x){strsplit(x, "V")[[1]][2]}))
Now you can sort your strings using vals
cf[order(vals)]
Solution 6 - R
Here's a base approach utilizing names
and sort
(Ananda's was pretty slick):
cf <- c("V440","V457","V116","V327","V446","V108",
"V155","V217","V120","V51","V477")
cf2 <- as.numeric(gsub("[^[:digit:]]", "", cf))
names(cf2) <- seq_along(cf2)
cf[as.numeric(names(sort(cf2)))]
## > cf[as.numeric(names(sort(cf2)))]
## [1] "V51" "V108" "V116" "V120" "V155" "V217" "V327"
## [8] "V440" "V446" "V457" "V477"