[SalesForce] How to sort by two fields using Comparable interface

I created a generic sorting utility using the comparable interface to test sorting by product name:

public class GenericSortingUtil {

public virtual class ObjWrapper implements Comparable {

    public sObject obj;

    public ObjWrapper() {}

    public ObjWrapper(Sobject obj) {
        this.obj = obj;

    }

    public virtual Integer compareTo(Object compareTo) {

        ObjWrapper compareToObj = (ObjWrapper)compareTo;

        if((String)obj.get('Name') > (String)compareToObj.obj.get('Name')) {
            return 1;
        }

        if((String)obj.get('Name') == (String)compareToObj.obj.get('Name')) {
            return 0;
        }

        return -1;
    }
}     

public static List<ObjWrapper> getProducts() {
    List<ObjWrapper> results = new List<ObjWrapper>();

    for (Product2 p : [select Name, ProductCode, Size__c from Product2 limit 100]) {
        results.add(new ObjWrapper(p));
    }
    return results;
} 
}

Child classs:

public class ShirtWrapper extends GenericSortingUtil.ObjWrapper {   

public override Integer compareTo(Object compareTo) {

    ShirtWrapper compareToObj = (ShirtWrapper)compareTo;

    integer nameOrder = super.compareTo(compareTo);
    return nameOrder == 0 ? getSizeOrder(String.valueOf(obj.get('Size__c'))) - getSizeOrder(String.valueOf(compareToObj.obj.get('Size__c'))) : nameOrder;
}   


public Integer getSizeOrder(string size) {
    Integer retval = -1;
    switch on size {
        when 'S' {
            retval = 0;
        } 
        when 'M' {
            retval = 1;
        }
        when 'L' {
            retval = 2;
        }
        when 'XL' {
            retval= 3;
        }
        when else {
            return retval;
        }
    }
    return retval;
}       
}

I can run the code in the anonymous window and get the correct results:

List<GenericSortingUtil.ObjWrapper> results = GenericSortingUtil.getProducts();
results.sort();
for(GenericSortingUtil.ObjWrapper ow : results) {
system.debug('********************* ' + ow.obj.get('Name'));
}

I'm trying to determine how I can sort by two fields so that each product grouping can be sorted by size. The products are clothing items. Each product has a series of sizes. For simplicity, the sizes are S, M, L, XL. What I am trying to achieve is sort by the size field as well as the product name.

For example, if I have the following products: black.v-neck.s, black.v-neck.m, black.v-neck.l, and black.v-neck.xl. I would want them sorted by smallest to largest:

black.v-neck.s
black.v-neck.m
black.v-neck.l
black.v-neck.xl

There is a size__c field for each product that holds the size value.

Any feedback on how to sort by a second field (size) so I can keep each product group in the proper order by size would be appreciated.

Best Answer

I think your best bet is going to be to extend your existing class, and implement the extra logic in the child class.

public class ShirtWrapper extends ObjWrapper{

    public Integer compareTo(Object compareTo) {

        ShirtWrapper compareToObj = (ShirtWrapper)compareTo;

        integer nameOrder = super.compareTo(compareTo);
        return nameOrder == 0 ? 
           getSizeOrder(String.valueOf(obj.get('Size__c'))) - getSizeOrder(String.valueOf(compareToObj.get('Size__c')))
           : nameOrder;

    }

    public static integer getSizeOrder(string size){
        switch on size {
            when 'S'{ return 0;}
            when 'M'{ return 1;}
            when 'L'{ return 2;}
            when 'XL'{ return 3;}
            when else{ throw new BadSizeException();}
            //I haven't tested whether the compiler will complain this doesn't always return,
            //if it does you can move the throw to the bottom of the method.
    }
}
Related Topic