Order a "mixed" vector (numbers with letters)

r, sorting

Solution

> library(gtools)
> mixedsort(alph)

[1] "7"   "8"   "9"   "10a" "10b" "10c" "11a" "11b" "11c" "12" 

To sort a data.frame you use `mixedorder` instead

> mydf <- data.frame(alph, USArrests[seq_along(alph),])
> mydf[mixedorder(mydf$alph),]

            alph Murder Assault UrbanPop Rape
Alabama        7   13.2     236       58 21.2
California     8    9.0     276       91 40.6
Colorado       9    7.9     204       78 38.7
Alaska       10a   10.0     263       48 44.5
Arizona      10b    8.1     294       80 31.0
Arkansas     10c    8.8     190       50 19.5
Florida      11a   15.4     335       80 31.9
Delaware     11b    5.9     238       72 15.8
Connecticut  11c    3.3     110       77 11.1
Georgia       12   17.4     211       60 25.8

`mixedorder` on multiple vectors (columns)

Apparently `mixedorder` cannot handle multiple vectors. I have made a function that circumvents this by converting all character vectors to factors with mixedsorted sorted levels, and pass all vectors on to the standard `order` function.

multi.mixedorder <- function(..., na.last = TRUE, decreasing = FALSE){
    do.call(order, c(
        lapply(list(...), function(l){
            if(is.character(l)){
                factor(l, levels=mixedsort(unique(l)))
            } else {
                l
            }
        }),
        list(na.last = na.last, decreasing = decreasing)
    ))
}

However, in your particular case `multi.mixedorder` gets you the same result as the standard `order`, since `V2` is numeric.

df <- data.frame(
    V1 = c("A","A","B","B","C","C","D","D","E","E"),
    V2 = 19:10,
    V3 = alph,
    stringsAsFactors = FALSE)

df[multi.mixedorder(df$V2, df$V3),]

   V1 V2  V3
10  E 10  12
9   E 11 11a
8   D 12 11b
7   D 13 11c
6   C 14   9
5   C 15   8
4   B 16 10c
3   B 17 10b
2   A 18 10a
1   A 19   7

Notice that

- `19:10` is equivalent to `c(19:10)`. `c` means concat, that is to make one long vector out of many short, but in you case you only have one vector (`19:10`) so there's no need to concat anything. However, in the case of `V1` you have 10 vectors of length 1, so there you need to concat, as you already do.

- You need `stringsAsFactors=FALSE` to not convert `V1` and `V3` to (incorrectly sorted) factors (which is default).

Problem

How can I order a vector like ``` c("7","10a","10b","10c","8","9","11c","11b","11a","12") -> alph ``` in ``` alph [1] "7","8","9","10a","10b","10c","11a","11b","11c","12" ``` and use it to sort a data.frame, like ``` V1 <- c("A","A","B","B","C","C","D","D","E","E") V2 <- 2:1 V3 <- alph df <- data.frame(V1,V2,V3) ``` and order the row to obtain (order V2 and then V3) ``` V1 V2 V3 C 1 9 A 1 10a B 1 10c D 1 11b E 1 12 A 2 7 C 2 8 B 2 10b E 2 11a D 2 11c ```

Original source