Usually in situations like this the job of the Comparator is to simple return the value of a compare from something else. For example, here is a Comparator that will alphabetize Fonts:
class FontAlphabetizer
implements Comparator<Font> {
@Override
public int compare(Font font1, Font font2) {
return font1.getName().compareTo(font2.getName());
}
}
That's actually pretty simple: getName returns a String and all we do is return the value of String's compareTo method.
Here it seems like what you have is an ArrayList<Map> and you want to sort the ArrayList based on a chosen value from the Map. So what you need is a Comparator<Map>. And you need to give the Comparator the key for the corresponding value that you want to sort by. This can be expressed generically like the following:
class MapValueComparator<K, V extends Comparable<V>>
implements Comparator<Map<K, V>> {
final K key;
MapValueComparator(K key) {
this.key = key;
}
@Override
public int compare(Map<K, V> map1, Map<K, V> map2) {
return map1.get(key).compareTo(map2.get(key));
}
}
That is a Comparator that compares Maps and it's specified in the declaration there that the Map's values must also be Comparable. It compares based on the value retrieved from the given key.
So for example if we have an ArrayList<Map<String, String>>, we can sort by the value from "town" like this:
static void sortByTown(List<Map<String, String>> list) {
Collections.sort(list, new MapValueComparator<String, String>("town"));
}
The hiccup is that you say you have town=Toronto, population=2,500,000 which indicates that the population you want to sort by is a String (since presumably it's in the same map as Toronto). Comparing population as String probably isn't desired because it will sort lexicographically (50 comes after 2,500,000 because 5 comes after 2). In that case the generic version might not work because you need to take an extra step of converting the value to a number.
class PopulationComparator
implements Comparator<Map<String, String>> {
@Override
public int compare(Map<String, String> map1, Map<String, String> map2) {
final Long pop1 = Long.valueOf(map1.get("population"));
final Long pop2 = Long.valueOf(map2.get("population"));
return pop1.compareTo(pop2);
}
}
(And as a side note if your population contains commas you'd need to format that before parsing it to a number. You can use replaceAll("\\D", "") to remove all non digits from a String.)
This is also a case where it could be advantageous to create a class for this instead of using a Map. Then you could have the numerical fields be number types. If you had a class, the comparison would be mostly the same though: just returning a comparison of a chosen field.