views:

117

answers:

6

I have this HashMap that I need to print out in ascending order according to the values contained in it (not the keys).

But the order when I print it out is seemingly random.

What's the best way to print it out in ascending value order?

Map<String, String> codes = new HashMap<String, String>();

codes.put("A1", "Aania");
codes.put("X1", "Abatha");
codes.put("C1", "Acathan");
codes.put("S1", "Adreenas");

In other words, the example above should print out as this:

A1, Aania
X1, Abatha
C1, Acathan
S1, Adreenas
A: 
  1. Create a TreeMap<String,String>
  2. Add each of the HashMap entries with the value as the key.
  3. iterate the TreeMap

If the values are nonunique, you would need a list in the second position.

bmargulies
Beautiful. Had to delete my answer :)
pst
Not quite right... "Red-Black tree based implementation of the SortedMap interface. This class guarantees that the map will be in ascending key order, sorted according to the natural order for the key's class (see Comparable), or by the comparator provided at creation time, depending on which constructor is used."You'll have it sorted by the keys, not the values.
I82Much
And thus edited.
bmargulies
A: 

Look here

Yanick Rochon
+4  A: 

You aren't going to be able to do this from the HashMap class alone.

I would take the Map<String, String> codes, construct a reverse map of TreeMap<String, String> reversedMap where you map the values of the codes Map to the keys (this would require your original Map to have a one-to-one mapping from key-to-value). Since the TreeMap provides Iterators which returns entries in ascending key order, this will give you the value/key combination of the first map in the order (sorted by values) you desire.

Map reversedMap<String, String> = new TreeMap<String, String>(codes.size());
for (Map.Entry entry : codes.entrySet()) {
    reversedMap.put(entry.getValue(), entry.getKey());
}

//then you just access the reversedMap however you like...
for (Map.Entry entry : reversedMap.entrySet()) {
    System.out.println(entry.getKey() + ", " + entry.getValue());
}

There are several collections libraries (commons-collections, Google Collections, etc) which have similar bidirectional Map implementations.

matt b
Why is the second loop necessary? Just create a temporary map and add from `codes` switching the key and value?
TheLQ
it's not necessary, it's an example of accessing the `reversedMap` and doing something with the entries
matt b
What if two entries in map has different keys but same value? this code will remove one of them...
Ankit
@akb this is why I said *this would require your original map to have a one-to-one mapping from key-to-value*
matt b
+4  A: 

You'll need to make a list of the keys, sort them according to the corresponding values, then iterate over the sorted keys.

Map<String, String> map = getMyMap();
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys, someComparator);
for (String key: keys) {
    System.out.println(key + ": " + map.get(key));
}

As for what to use for someComparator, here are some handy, generic Comparator-creating routines I often find useful. The first one sorts by the values according to their natural ordering, and the second allows you to specify any arbitrary Comparator to sort the values:

public static <K, V extends Comparable<? super V>>
        Comparator<K> mapValueComparator(final Map<K, V> map) {
    return new Comparator<K>() {
        public int compare(K key1, K key2) {
            return map.get(key1).compareTo(map.get(key2));
        }
    };
}

public static <K, V>
        Comparator<K> mapValueComparator(final Map<K, V> map,
                                         final Comparator<V> comparator) {
    return new Comparator<K>() {
        public int compare(K key1, K key2) {
            return comparator.compare(map.get(key1), map.get(key2));
        }
    };
}
Sean
+1  A: 

The simplest solution would be to use a sorted map like TreeMap instead of HashMap. If you do not have control over the map construction, then the minimal solution would be to construct a sorted set of keys. You don't really need a new map.

Set<String> sortedKeys = new TreeSet<String>();
sortedKeys.addAll(codes.keySet());

for(String key: sortedKeys){
    println(key  + ":" + codes.get(key));
}
aar
A: 

You can use a list of the entry set rather than the key set and it is a more natural choice given you are sorting based on the value. This avoids alot of unneeded lookups in the sorting and printing of the entries.

Map<String, String> map = ...
List<Map.Entry<String, String>> listOfEntries = new ArrayList<Map.Entry<String, String>>(map.entrySet());
Collections.sort(listOfEntries, new SortByValueComparator());
for(Map.Entry<Map.Entry<String, String>> entry: listOfEntries)
   System.out.println(entry);

static class SortByValueComparator implements Comparator<Map.Entry<String, String>> {
   public int compateTo(Map.Entry<String, String> e1, Map.Entry<String, String> e2) {
       return e1.getValue().compateTo(e2.getValue());
   }
}
Peter Lawrey