3

I have a Map which will store list of Contact as values.

like Map<Id,List<Contact>> myMap = new Map<Id,List<Contact>>();

here Id is Account Id and Contact is list of related contacts.

I want to sort List based on created date and then sort Map Id according to that E.g. I have two Account A and B Account A contains three Contact c1,c2,c3 with created date 15 July Account B contains two contact cb1,cb2 with created date 11 July

Now since Account B's contacts are created first so I want to display Account B first then Account A.

I'm not able to sort Map based on it's values. Is there any other approach to solve it?

5

In Apex, a Map is not sortable by definition. You can use a List to store the keys, sort that as you wish, then iterate through it. Note that you can retrieve child object lists through your query, so it may not be necessary to even use a Map.

List<Id> orderedAccountIds = new List<Id>();
Map<Id, List<Contact>> accountIdTocontacts = new Map<Id, List<Contact>>();
for (Account record : [
    SELECT Id, (SELECT Id FROM Contacts)
    FROM Account ORDER BY CreatedDate DESC
]){
    orderedAccountIds.add(record);
    accountIdToContacts.put(record.Id, record.Contacts);
}

You might need to adjust the syntax above to use the List and Map as properties. It's hard to identify your surrounding context.

0

EDIT: the following code alters (sorts) the way Apex loops through map keys, but you need to restructure the existing map and put the key/value pairs in it in the desired order. Instead of using earliest date as the baseline, it uses the number of records contained at each map key's list. This code temporarily appends an integer and delimiter on the front of an Id (which acts as the temporary key), then we can sort the keys ascending, then we parse the ids out of the extended keys using the delimiter and put those keys back into the map in the order we want.

 * Sort a string to list map by the number of items in each list ascending.
 * Example param: We have a quote id to quote lines map, where each quote id is mapped to associated list of quote lines.
 *   quote id A (first quote id in the map) has 5 quote lines
 *   quote id B (second quote in id the map) has 3 quote lines
 *   quote id C (third quote id in the map) has 11 quote lines
 *   
 *   After sorting:
 *   quote id B (first quote id in the map, 3 quote lines)
 *   quote id A (second quote id in the map, 5 quote lines)
 *   quote id C (third quote id in the map, 11 quote lines)
 * 
 * @param  mapToSort -> map of: String to list of sobjects to sort. 
 * @return sortedMap -> a sorted map by the number of items in each of the key's lists ascending


public static Map<String, List<sObject>> mapSorter(Map<String, List<sObject>> mapToSort) {
    Map<String, List<sObject>> prepSortedMap = new Map<String, List<sObject>>();
    for(String key : mapToSort.keySet()) {
        List<sObject> childObjList = mapToSort.get(key) == null ? new List<sObject>() : mapToSort.get(key);
        String numOfChildren = String.valueOf(childObjList.size());
        String placeholderDigits = '00000';
        String keyPrefix = placeholderDigits.substring(0, placeholderDigits.length() - numOfChildren.length()) + numOfChildren;
        prepSortedMap.put(keyPrefix + '*' + key, childObjList);
    }

    List<String> sortedList = new List<String>(prepSortedMap.keyset());
    sortedList.sort();

    Map<String, List<sObject>> sortedMap = new Map<String, List<sObject>>();
    for(String idKey : sortedList) {
        Id idFromIdKey = Id.valueOf(idKey.substring(idKey.indexOf('*') + 1, idKey.length()));
        sortedMap.put(idFromIdKey, prepSortedMap.get(idKey));
    }

    return sortedMap;
}
4
  • I'm not sure this code does what you think it does. Have you done any unit testing to see if order is preserved in the way you expect?
    – Adrian Larson
    Jan 30 '19 at 18:40
  • Yes I have confirmed this works in execute anonymous by printing off the map keys in a loop. Basing the sort on dates (what OP is trying to do) is going to be a little different (instead of basing the sort on number of records) but the takeaway here is that you can manipulate the order in which apex loops through map keys. Jan 31 '19 at 19:50
  • 1
    The order of iteration of Map keys is documented to be deterministic, but as far as I know it's not documented or guaranteed to be any specific deterministic order. While it seems unlikely Salesforce would go out of their way to use an order other than insertion order, it's close enough to undefined behavior to make me leery.
    – David Reed
    Jan 31 '19 at 23:27
  • Thanks for the reply; I realize I mispoke. The way Visualforce loops through map keys is based on a combination of alphabet and number sequence. Example: map has 3 keys that are strings: '111', '333', and '222'. Map key 1 will get looped through first, map key 3 will get looped through second, and Map key 2 will get looped through third. Apex loops through the keys in the order they were put into the map, from what I've seen. I'll update my answer. Feb 1 '19 at 2:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.