public class superSort { /*This method takes 3 arguments, the List of objects to sort, the field to sort, and the order, asc or desc*/ public static void sortList(List items, String sortField, String order){ /*I must give credit where it is due as the sorting algorithm I am using is the one supplied by Andrew Waite here: http://blog.sforce.com/sforce/2008/09/sorting-collect.html */ Boolean isSortFieldReference = false; Map referenceName; /*Determine the type of the field that needs to be sorted, if it is a reference we will want sort by the name of the related object, not the ID itself*/ if(items[0].getSObjectType().getDescribe().fields.getMap().get(sortField).getDescribe().getType().Name() == 'REFERENCE'){ isSortFieldReference = true; referenceName = new Map(); /*Determine the type of this object and populate the Id to Name map*/ Set referenceIds = new Set(); for(sObject s : items){ referenceIds.add((Id)s.get(sortField)); } String objectID = (String)items[0].get(sortField); String prefix = objectID.substring(0,3); String objectType; Map gd = Schema.getGlobalDescribe(); for(Schema.SObjectType s : gd.values()){ if(prefix == s.getDescribe().getKeyPrefix()){ objectType = s.getDescribe().Name; } } //Query the related objects for the name and populate the Id -> Name map String queryString = 'select Id, Name from ' + objectType + ' where ID IN :referenceIDs'; for(sObject s : Database.query(queryString )){ referenceName.put((Id)s.get('Id'),(String)s.get('Name')); } } /*Declare a list that will contain the sorted results. I think this is one of the coolest parts of this method as the system will not let you declare a list of sObjects (List objects = new List();) but using a wrapper class you can bypass this system limitation to create this type of list */ List resultList = new List(); //Create a map that can be used for sorting Map> objectMap = new Map>(); for(sObject ob : items){ if(isSortFieldReference == false){ if(objectMap.get(ob.get(sortField)) == null){ objectMap.put(ob.get(sortField), new List()); } cObject o = new cObject(ob); objectMap.get(ob.get(sortField)).add(o); }else{ if(objectMap.get(referenceName.get((Id)ob.get(sortField))) == null){ objectMap.put(referenceName.get((Id)ob.get(sortField)), new List()); } cObject o = new cObject(ob); objectMap.get(referenceName.get((Id)ob.get(sortField))).add(o); } } //Sort the keys List keys = new List(objectMap.keySet()); keys.sort(); for(object key : keys){ resultList.addAll(objectMap.get(key)); } //Apply the sorted values to the source list items.clear(); if(order.toLowerCase() == 'asc'){ for(cObject ob : resultList){ items.add(ob.obj); } }else if(order.toLowerCase() == 'desc'){ for(integer i = resultList.size()-1; i >= 0; i--){ items.add(resultList[i].obj); } } } public class cObject{ sObject obj {get; set;} public cObject(sObject obj){ this.obj = obj; } } /*Some test methods that provide 100% coverage public static testMethod void sortAscendingTest(){ List opps = new List(); for(integer i = 0; i<1000; i++){ opps.add(new Opportunity(Name = 'test' + i, Amount = 1000 * Math.random())); } Test.startTest(); Long start = system.currentTimeMillis(); sortList(opps,'Amount','asc'); system.debug(system.currentTimeMillis() - start); Test.stopTest(); //Assert the list was sorted correctly Decimal assertValue = -1; for(Opportunity o : opps) { System.debug('Opp value: ' + o.amount); System.assert(assertValue <= o.amount); assertValue = o.amount; } } public static testMethod void sortDescendingTest(){ List opps = new List(); for(integer i = 0; i<1000; i++){ opps.add(new Opportunity(Name = 'test' + i, Amount = 1000 * Math.random())); } Test.startTest(); sortList(opps,'Amount','desc'); Test.stopTest(); //Assert the list was sorted correctly Decimal assertValue = 1001; for(Opportunity o : opps) { System.debug('Opp value: ' + o.amount); System.assert(assertValue >= o.amount); assertValue = o.amount; } }*/ }