# 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.

This topic: Main > WebHome > Seminars > RClinic > MultiSortFunction
Topic revision: revision 2
 
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