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