# this first multisort was the original way I wrote it
# it could have a maximum of four columns to sort
# multisort<-function(frame, col1, dec1=F, col2, dec2=F, col3="", dec3=F, col4="", dec4=F){
# #there are three required arguments, frame, col1, and col2
# #this means you must have at least two columns from a dataset that you want to sort
#   if(col4=="") {
#     if(col3=="") {
#       #only have two columns to sort
#       sub<-frame[order(getVal(frame,col2),decreasing=dec2),]
#     } else {
#       #three columns to sort
#       sub<-multisort(frame,col2,dec2,col3,dec3)
#     }
#   } else {
#     #must sort all four columns
#     if(col3=="") {
#       #quit trying to mess up the function
#       sub<-multisort(frame,col2,dec2,col4,dec4)
#     }
#     sub<-multisort(frame,col2,dec2,col3,dec3,col4,dec4)
#   }
#   sub[order(getVal(sub,col1),decreasing=dec1),]
# }
#to sort just numeric values
#x[order(x$SAL,-x$AB),]

tmp<-read.csv('kforce.csv', header=T)
multisort<-function(frame, col1, dec1, col2, dec2, ...) {
    #before doing any sorting, convert arguments into two vectors
    mylist<-list(...)
    col<-as.vector(c(col1,col2))
    dec<-as.vector(c(dec1,dec2))
    count<-6
    for(i in mylist) {
        if(i==TRUE || i==FALSE) {
            if(count%%2==1) {
                dec[count%/%2]<-i
                count<-count+1
            }
        } else {
            if(count%%2==0) { count<-count+1 } 
            else { count<-count+2 }
            #set vectors, default dec to FALSE
            col[count%/%2]<-i
            dec[count%/%2]<-F
        }
    }
    #the function parameters must be valid now
    if(length(col)>2) {
        extraArgs<-vector()
        count<-1
        for(i in col) {
            pos=(count+1)%/%2
            if(count>5) {
                #append value to extraArgs
                extraArgs[count-6]<-col[pos]
                extraArgs[count-5]<-dec[pos]
            }
            count<-count+2
        }
        if(length(col)==3) {
            sub<-multisort(frame,col[2],dec[2],col[3],dec[3])
        } else {
            sub<-multisort(frame,col[2],dec[2],col[3],dec[3],extraArgs)
        }
    } else {
        #only two columns to sort - this is where the recursion ends!
        sub<-frame[order(getVal(frame,col2),decreasing=dec2),]
    }
    sub[order(getVal(sub,col1),decreasing=dec1),]
}
getVal<-function(frame,col) {
    eval(parse(text=paste(quote(frame),col,sep="$")))
}

multisort(tmp,"CO",T,"SAL",F,"POS",T,"AB")
#there are a few rules to make sure this works
#you must set descending to T or F for the first two columns (3rd & 5th argument)
#don't set arguments equal to a variable name (except for the first 5 arguments)
#the 6th argument (assuming it's a legitimate column) will be set to col3 regardless if set to something in function call

  • Another solution from Tatsuki Koyama -- much shorter R code which probably does the same thing:

sort.mat3 <- function(mat, sort.by, decreasing = F){
     # This will sort a matrix or a data.frame based on the columns 'sort.by.'
     # 'sort.by' and 'decreasing' are  vectors of any length with length(sort.by) >= length(decreasing).

        v <- rev(sort.by) ; de <- decreasing
        if( length(de) < length(v) ){de[(length(de)+1) : length(v)] <- F}

        for(i in 1:length(v)){
                mat <- mat[order(mat[,v[i]], decreasing=rev(de)[i]),]}

        mat}

   # To reproduce Cole's example,
   # > multisort(tmp,"CO",T,"SAL",F,"POS",T,"AB")
   # do
   sort.mat3(tmp, c(6,5,3), c(T, F, T))
   # because "CO" is the 6th column, "SAL" is 5th and "POS" is 3rd column.
Topic revision: r2 - 17 Jan 2007, ColeBeck
 

This site is powered by FoswikiCopyright © 2013-2022 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Vanderbilt Biostatistics Wiki? Send feedback