[SalesForce] Sorting list by custom field multiple times

I am working on an apex trigger. I have a list that I need to sort by a date field, do some processing, then sort by another date field, and do more processing etc 5 times. When I do the initial SOQL query I can sort by Date1 using ORDER BY. I can even sort by Date2 by using a wrapper class as outlined in the apex help documentation here. But I'm not sure how to then a Date3, Date4, Date5 etc.

I'm thinking I need to modify the wrapper class so that it will accept some inputs and output different types of sorts, but I'm not sure how to do this.

The wrapper class where I tried making the field to be sorted on an input

global class CustomWrapper implements Comparable {

public Custom_Object__c CO1;
public String sortField;

public CustomWrapper(Custom_Object__c CO) {
    CO1 = CO;
}

global Integer compareTo(Object compareTo) {
    CustomWrapper compareToOppy = (CustomWrapper)compareTo;

    Integer returnValue = 0;
    if(sortField=='Date1'){       
        if (CO1.Date1 == compareToOppy.CO1.Date1) {
            returnValue = 0;
        } else if (CO1.Date1 > compareToOppy.CO1.Date1) {
            returnValue = 1;
        } else if (CO1.Date1 < compareToOppy.CO1.Date1) {
            returnValue = -1;
        }
    }
    //...More of the same for different sortFields
    return returnValue; 

}
}

Best Answer

A fully plug-and-play solution would need a more powerful Sortable class, which I've written once or twice before. This should be a top-level class, because you ultimately want some static variables to make life easier for yourself. Here goes.


public class Sortable implements Comparable {
    // interface to compare
    public interface SortMethod {
        Integer compareTo(Object a, Object b);
    }

    // Example: Date interface
    public class DateFieldSort implements SortMethod {
        Boolean sortAsc;
        SObjectField field;

        public DateFieldSort(SObjectField sortField) {
            this(sortField, true);
        }
        public DateFieldSort(SObjectField sortField, Boolean sortAsc) {
            this.sortAsc = sortAsc;
            field = sortField;
        }
        public Integer compareTo(Object a, Object b) {
            SObject left = (SObject)a, right = (SObject)b;
            Date v1 = (Date)left.get(field), v2 = (Date)right.get(field);
            if(v1 == null) {
                v1 = Date.newInstance(0, 0, 0);
            }
            if(v2 == null) {
                v2 = Date.newInstance(0, 0, 0);
            }
            return
                (sortAsc ? 1: -1) * (
                (v2.year() << 9 | v2.month() << 5 | v2.day()) -
                (v1.year() << 9 | v1.month() << 5 | v2.day())
                );
        }
    }

    // set this value before calling sort
    public static SortMethod compareMethod;

    // Constructor accepting a value
    public Sortable(Object value) {
        this.value = value;
    }

    // Private storage
    Object value;

    // Get value back
    public Object getValue() {
        return value;
    }

    // implements Comparable
    public Integer compareTo(Object other) {
        return compareMethod.compareTo(this.value, ((Sortable)other).value);
    }
}

Now that you've got this, you're almost ready to sort; it just takes three steps.

Step 1

Convert your records to Sortable items:

Sortable[] values = new Sortable[0];
for(Sobject record: Trigger.new) {
  values.add(new Sortable(record));
}

Step 2

Specify your sorting method.

Sortable.compareMethod = new Sortable.DateFieldSort(Opportunity.CloseDate);

Step 3

Sort your list.

values.sort();

You can repeat steps 2 and three as frequently as you like. If you don't like the getValue part, you could also just make your Object variable public. To implement new sort methods, you just need to add more implements SortMethod classes as you desire.

Don't worry about the << and | parts if you don't fully understand them, we're basically converting the dates into bitmaps and subtracting them; the result is that the number will either be positive, negative, or 0, and the sort algorithm will take care of the rest.

In case your curious, the bitmap looks like this:

          Year              Month  Day
___________________________||___||_____
|                          ||   ||    |
0000 0000 0000 0000 0000 0000 0000 0000
Related Topic