I'm trying to sort a character vector in a natural order (as a human would sort it) but considering case differences. For example, in the vector below I would like to sort all the small "m" and the big "M" independently.
x<- c("m10", "M10", "m11", "m12", "m2", "M2", "m3", "M3", "m4", "M4", "yo1", "yo2")
so that it looks like:
DesiredSort(x)
[1] "M2" "M3" "M4" "M10" "m2" "m3" "m4" "m10" "m11" "m12" "yo1" "yo2"
From here I got how to make sort take case into account:
sortC <- function(...) {
a <- Sys.getlocale("LC_COLLATE")
on.exit(Sys.setlocale("LC_COLLATE", a))
Sys.setlocale("LC_COLLATE", "C")
sort(...)
}
sortC(x)
[1] "M10" "M2" "M3" "M4" "m10" "m11" "m12" "m2" "m3" "m4" "yo1" "yo2"
But that does not give the natural order. I know mixedsort from gtools will properly put m2 before m10, so that:
mixedsort(x)
[1] "m2" "M2" "m3" "M3" "m4" "M4" "m10" "M10" "m11" "m12" "yo1" "yo2"
But mixedsort specifically ignores case of character string, so doing a similar function to SortC does not work.
I have several vectors to sort in this way, and they include characters not included in the example, so it would be great to find a general way of doing this.
Ideas? Maybe there is something obvious I'm missing. Thanks.
How general do you need the solution to be? This custom solution below fits your dataset, but it isn't entirely clear (at least to me) what you want to happen in the general case of a vector containing arbitrary strings.
DesiredSort <- function(x)
{
library(stringr)
locale <- Sys.getlocale("LC_COLLATE")
on.exit(Sys.setlocale("LC_COLLATE", locale))
Sys.setlocale("LC_COLLATE", "C")
x_matches <- str_match(x, "(^[[:alpha:]]+)([[:digit:]]+)")[, 2:3]
x_data <- data.frame(
letter = x_matches[, 1],
number = as.numeric(x_matches[, 2])
)
o <- with(x_data, order(letter, number))
x[o]
}
x <- c("m10", "M10", "m11", "m12", "m2", "M2", "m3", "M3", "m4", "M4", "yo1", "yo2")
expected <- c("M2", "M3", "M4", "M10", "m2", "m3", "m4", "m10", "m11", "m12", "yo1", "yo2")
stopifnot(identical(DesiredSort(x), expected))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With