[SalesForce] How to sort Map by values

I need to loop through Accounts and then on all of the Contacts for those Accounts. I need to find what is the address with the most occurrences in Contacts for each Account and update the Account with that address.
I can loop through Accounts and Contacts just fine but getting the address and finding the one that most Contacts have is getting tricky.
This is my code so far:

public static void completeaddresses(){
    List<Account> acctList = new List<Account>();
    acctList = [SELECT Id, BillingState, BillingPostalCode, BillingCity,BillingStreet, BillingCountry, BillingAddress, (SELECT Id, contact.MailingAddress, contact.MailingStreet, contact.MailingCity, contact.MailingState, contact.MailingPostalCode, contact.MailingCountry FROM account.contacts WHERE contact.MailingStreet!='' OR contact.MailingCity!='' OR contact.MailingPostalCode!='' OR contact.MailingCountry!='' OR contact.MailingState!='') FROM Account WHERE BillingState ='' AND BillingPostalCode ='' AND BillingCity = '' AND BillingStreet = ''];

    Map<Address, Integer> addresses = new Map<Address, Integer>();
    List<Address> addressList = new List<Address>();

    for (Account acct:acctList) {
        for (Contact cont:acct.contacts) {
            if (!addresses.containsKey(cont.MailingAddress)) {
                addresses.put(cont.MailingAddress,0);
            }
            Integer currentCount = addresses.get(cont.MailingAddress) + 1;
            addresses.put(cont.MailingAddress, currentCount);
        }
        addressList.addAll(addresses.keySet());
        addressList.sort();
    }
}

The issue is, it sorts by key not by value, if I could sort by value, then I can update the account and I'd be done. I'd appreciate if someone can let me know if I can sort by value and how.
Thanks.

Best Answer

Your best bet is to write a wrapper for this.

public class AddressWrapper implements Comparable {
    public Address address;
    public Integer counter;
    public AddressWrapper(Address address, Integer counter) {
        this.address = address;
        this.counter = counter;
    }
    public Integer compareTo(Object other) {
        return counter-((AddressWrapper)other).counter;
    }
}

Which you would then populate:

AddressWrapper[] addressList = new AddressWrapper[0];
for(Address key: addresses.keyset()) {
    addressList.add(new AddressWrapper(key, addresses.get(key)));
}
addressList.sort();
// addressList[0].address contains the most used address

I've edited the changes together and cleaned up the code; this code runs in execute anonymous:

public class AddressWrapper implements Comparable {
    public Address address;
    public Integer counter;
    public AddressWrapper(Address address, Integer counter) {
        this.address = address;
        this.counter = counter;
    }
    public Integer compareTo(Object other) {
        return counter-((AddressWrapper)other).counter;
    }
}

public static void completeaddresses() {
    Account[] acctList = [
        SELECT BillingState, BillingPostalCode, BillingCity, BillingStreet, BillingCountry, BillingAddress, 
            (SELECT MailingAddress, MailingStreet, MailingCity, MailingState, MailingPostalCode, MailingCountry 
             FROM account.contacts WHERE MailingStreet <> NULL OR MailingCity <> NULL OR
                  MailingPostalCode <> NULL OR MailingCountry <> NULL OR MailingState <> NULL)
        FROM Account
        WHERE BillingState <> NULL AND BillingPostalCode <> NULL AND BillingCity <> NULL AND BillingStreet <> NULL];

    for (Account acct:acctList) {
        Map<Address, Integer> addresses = new Map<Address, Integer>();
        for (Contact cont:acct.contacts) {
            if (!addresses.containsKey(cont.MailingAddress)) {
                addresses.put(cont.MailingAddress,0);
            }
            Integer currentCount = addresses.get(cont.MailingAddress) + 1;
            addresses.put(cont.MailingAddress, currentCount);
        }
        AddressWrapper[] addressList = new AddressWrapper[0];
        for(Address key: addresses.keyset()) {
            addressList.add(new AddressWrapper(key, addresses.get(key)));
        }
        addressList.sort();
        // addressList[0].address contains the most used address
    }
}
Related Topic