You have to implement a Wrapper class with comparable interface for this to happen.
To implement a custom sort order for sObjects in lists, create a wrapper class for the sObject and implement the Comparable interface. The wrapper class contains the sObject in question and implements the compareTo method, in which you specify the sort logic.
Eg:
global class OpportunityWrapper implements Comparable {
public Opportunity oppy;
// Constructor
public OpportunityWrapper(Opportunity op) {
oppy = op;
}
// Compare opportunities based on the opportunity amount.
global Integer compareTo(Object compareTo) {
// Cast argument to OpportunityWrapper
OpportunityWrapper compareToOppy = (OpportunityWrapper)compareTo;
// The return value of 0 indicates that both elements are equal.
Integer returnValue = 0;
if (oppy.Amount > compareToOppy.oppy.Amount) {
// Set return value to a positive value.
returnValue = 1;
} else if (oppy.Amount < compareToOppy.oppy.Amount) {
// Set return value to a negative value.
returnValue = -1;
}
return returnValue;
}
}
And then to Sort just call Sort Method after adding records to your wrapper list
OpportunityWrapper[] oppyList = new List<OpportunityWrapper>();
Date closeDate = Date.today().addDays(10);
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Edge Installation',
CloseDate=closeDate,
StageName='Prospecting',
Amount=50000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='United Oil Installations',
CloseDate=closeDate,
StageName='Needs Analysis',
Amount=100000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Grand Hotels SLA',
CloseDate=closeDate,
StageName='Prospecting',
Amount=25000)));
// Sort the wrapper objects using the implementation of the
// compareTo method.
oppyList.sort();
So in your case, the CaseWrapper will compare CUID__c to determine sorting order in the compareTo method.
Src: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_list_sorting_sobject.htm
Answer from Pranay Jaiswal on Stack ExchangeVideos
You have to implement a Wrapper class with comparable interface for this to happen.
To implement a custom sort order for sObjects in lists, create a wrapper class for the sObject and implement the Comparable interface. The wrapper class contains the sObject in question and implements the compareTo method, in which you specify the sort logic.
Eg:
global class OpportunityWrapper implements Comparable {
public Opportunity oppy;
// Constructor
public OpportunityWrapper(Opportunity op) {
oppy = op;
}
// Compare opportunities based on the opportunity amount.
global Integer compareTo(Object compareTo) {
// Cast argument to OpportunityWrapper
OpportunityWrapper compareToOppy = (OpportunityWrapper)compareTo;
// The return value of 0 indicates that both elements are equal.
Integer returnValue = 0;
if (oppy.Amount > compareToOppy.oppy.Amount) {
// Set return value to a positive value.
returnValue = 1;
} else if (oppy.Amount < compareToOppy.oppy.Amount) {
// Set return value to a negative value.
returnValue = -1;
}
return returnValue;
}
}
And then to Sort just call Sort Method after adding records to your wrapper list
OpportunityWrapper[] oppyList = new List<OpportunityWrapper>();
Date closeDate = Date.today().addDays(10);
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Edge Installation',
CloseDate=closeDate,
StageName='Prospecting',
Amount=50000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='United Oil Installations',
CloseDate=closeDate,
StageName='Needs Analysis',
Amount=100000)));
oppyList.add( new OpportunityWrapper(new Opportunity(
Name='Grand Hotels SLA',
CloseDate=closeDate,
StageName='Prospecting',
Amount=25000)));
// Sort the wrapper objects using the implementation of the
// compareTo method.
oppyList.sort();
So in your case, the CaseWrapper will compare CUID__c to determine sorting order in the compareTo method.
Src: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_list_sorting_sobject.htm
In 2024 things have improved. Salesforce introduced the Comparator interface, something that Java had at least since version 1.2. No need for wrappers or another query. In order to sort according to a field CUID__c of the Case object, you'd implement a class like this:
public class CaseCUIDComparator implements Comparator<Case> {
public Integer compare(Case case0, Case case1) {
if(case0.CUID__c == null) return 1;
if(case1.CUID__c == null) return -1;
return case0.CUID__c < case1.CUID__c ? -1 : 1;
}
}
The unit test demonstrates its use and its impact:
@IsTest
private static void verifyComparator() {
List<Case> cases = new List<Case>{
new Case(CUID__c = 'B'),
new Case(CUID__c = null),
new Case(CUID__c = 'A'),
new Case(CUID__c = 'D'),
new Case(CUID__c = 'A'),
new Case(CUID__c = 'C')
};
Test.startTest();
cases.sort(new CaseCUIDComparator());
Test.stopTest();
Assert.areEqual('A', cases[0].CUID__c);
Assert.areEqual('A', cases[1].CUID__c);
Assert.areEqual('B', cases[2].CUID__c);
Assert.areEqual('C', cases[3].CUID__c);
Assert.areEqual('D', cases[4].CUID__c);
Assert.areEqual(null, cases[5].CUID__c);
}
You really should bulkify this code, i.e. not run a query inside a loop which could cause potentially cause issues with the governor limits, and since you just want the combined list for all Job__c records this makes your ordering easy too — you can do it in the query!
The code you want to change is this:
// Select relevant Job Occurrence objects
List<Job_Occurrence__c> jobOccuList = new List<Job_Occurrence__c>();
for (Job__c job : jobList) {
Job_Occurrence__c jobOccurrence = [SELECT Id, Job__c,
Schedule_Start_Date__c
FROM Job_Occurrence__c
WHERE Job__c =: job.Id];
if((jobOccurrence != null) && (jobOccurrence.Id != null)) {
jobOccuList.add(jobOccurrence);
}
}
Essentially we can optimise this to not only use one query instead of N (where N is jobList.size()) and get them ordered at the same time. First we need to gather the list of Job__c IDs, and then we can use the IN statement in the WHERE clause of the SOQL:
// Select relevant Job Occurrence objects
List<Job_Occurrence__c> jobOccuList;
Set<Id> setJobIds = new Set<Id>();
setJobIds.addAll(jobList);
// get the job occurances starting with the latest, use ASC for reverse!
jobOccuList = [SELECT Id, Job__c, Schedule_Start_Date__c
FROM Job_Occurrence__c
WHERE Job__c IN : setJobIds
ORDER BY Schedule_Start_Date__c DESC];
Finally, if you need to be able to easily map back from the Job_Occurrence_c records to Job_c records, you could replace the set with a map as below, though given that you just want this list I don't think it's needed here (just providing it for completeness).
Map<Id, Job__c> mapJobs = new Map<Id, Job__c>();
for (Job__c job : jobList) {
mapJobs.put(job.Id, job);
}
** snip **
for (Job_Occurrence__c jobOccu : jobOccuList) {
Job__c theJob = mapJobs.get(jobOccu.Job__c);
// do stuff with the job
}
All of this code has been written in browser, so there may be some syntax errors but it should be good!
You can try :
liDates.sort();
It's working for me.
Cheers
This is a general approach I'd suggest you consider taking considering the nature of your data.
If you don't want to use comparable, you will need to sort based on the "major" version, followed by the "minor" (for each major version), then each "finest" version (for the minor version). That will allow you to deal with the ones that don't have finer levels or those that don't use numbers like your 5.x
Use the '.' as separators to know what portions of your string to use to sort on for each level. You may want to save the results to a map by level (or something along those lines) where you can pull the results from each out and not have deeply nested loops in your code. I would use a RegEx pattern to assist with the coding.
EDIT
In response to comments...
Note: I have not tested the code below, but it does appear that it will compile.
List<String> src = new List<String>{
'7.1.2', '8.1.3', '11.0.5', '5.x', '10.0.89', '12.13.14'};
// declare maps and lists you will need
map<string, string>srcOrderMap = new map<string, string>();
map<string, list<string>>srcOrderLstMap = new map<string, List<string>>();
Integer count = 0;
integer iString = string.valueOf(count);
integer iString=string.valueOf(count);
list<string>b_count = new list<string>();
// create map for where you started from for complete string and list string
for(string s:src){
b_count=b.split('.');
srcOrderMap.put(iString,b_count);
srcOrderMap.put(iString,s);
count++;
}
// declare variables for next loop
map<string, string>srcCol0OrderMap = new map<string, string>();
map<string, string>srcCol1OrderMap = new map<string, string>();
map<string, string>srcCol2OrderMap = new map<string, string>();
list<string>sArrayCol0 = new list<string>();
list<string>sArrayCol1 = new list<string>();
list<string>sArrayCol2 = new list<string>();
// create maps for each column and lists of those values
for(integer s=0;s=srcOrderMap.size();s++){
for(integer c=0;c<3;c++){
if(c == 0){
sArrayCol0.add.srcOrderMap.get(string.valueOf(s)[0]);
}
if(c == 1){
sArrayCol1.add.srcOrderMap.get(string.valueOf(s)[1]);
}
if(c == 2){
sArrayCol2.add.srcOrderMap.get(string.valueOf(s)[2]);
}
srcCol0OrderMap.put(string.valueOf(s), sArrayCol0[string.valueOf(s)]);
srcCol1OrderMap.put(string.valueOf(s), sArrayCol1[string.valueOf(s)]);
srcCol2OrderMap.put(string.valueOf(s), sArrayCol2[string.valueOf(s)]);
}
}
Now you can do a sort on column 0, after which you can do a sub-sort on column1 where any values in column 0 are the same to determine which value gets moved up or down in your map.
// sort the values in column 0
sArrayCol0.sort();
I'll leave it to you to determine how you want to find the duplicate values in the list. There are lots of solutions to that problem you should be able to find on your own.
Once you have the sorted column 0 results, all you need to do is go back to your original source map and retrieve the original values that are also ready for you in sArrayCol1 where they're ready for you to sort() and compare. The results of that sort will determine which one of the values in Col 0 "wins". If both are equal, then you sort again on based on the values found in sArrayCol2 as once again are referenced in the original source map.
That's the reason I recommended using maps, so you can keep track of these values and will always be able to go back and reference them from where you began as you re-order your records at different levels. I hope this provides you with the "map" you need to reach your destination.
Apex has a Version class that supports major.minor and major.minor.patch numbering. If you work with those objects:
List<Version> src = new List<Version>{
new Version(7, 1, 2),
new Version(8, 1, 3),
...
};
you get sorting for free (as compareTo is implemented) where this sorts in place:
src.sort();
and the string format for each Version is as expected e.g. "7.1.2".
Note that there is no support for your "5.x" though; if you need that you will have to create your own class as David discusses.