33

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
2
  • 1
    possible duplicate: stackoverflow.com/questions/109383/… Commented Aug 31, 2010 at 0:38
  • 7
    Just curious. What is the use case? My guess is you have chosen a wrong data structure and trying to tweak it to suit your specs. Commented Aug 31, 2010 at 5:25

13 Answers 13

41

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<String, String> reversedMap = new TreeMap<String, String>(codes);

//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.

Sign up to request clarification or add additional context in comments.

7 Comments

Why is the second loop necessary? Just create a temporary map and add from codes switching the key and value?
it's not necessary, it's an example of accessing the reversedMap and doing something with the entries
What if two entries in map has different keys but same value? this code will remove one of them...
@akb this is why I said this would require your original map to have a one-to-one mapping from key-to-value
System.out.println(entry.getValue() + ", " + entry.getKey()); to reproduce OP's original print outs
|
11

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));
        }
    };
}

Comments

6

It's time to add some lambdas:

codes.entrySet()
    .stream()
    .sorted(Comparator.comparing(Map.Entry::getValue))
    .forEach(System.out::println);

6 Comments

This does not print the String value, unless I'm missing something here.
@almostabeginner Code forEach(System.out::println) will print every entry. Check this
I think this only prints the address, rather than the value? I tried it but didn't work. My map contains two objects, the key being a "person" object, which has a firstname, lastname field etc, I want to print firstname, I don't see how this code would do that? Thanks for your time.
@almostabeginner To be precise, this code prints all Entry's in map, calling their toString method implicitly. If you want to print keys, or some field in key, you can do something like this: codes.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue)).map(Map.Entry::getKey).map(Person::getLastName).forEach(System.out::println);
How to use this with a logger ? I don't want to Syso ! Thanks :)
|
5

the for loop of for(Map.Entry entry: codes.entrySet()) didn't work for me. Used Iterator instead.

Iterator<Map.Entry<String, String>> i = codes.entrySet().iterator(); 
while(i.hasNext()){
    String key = i.next().getKey();
    System.out.println(key+", "+codes.get(key));
}

1 Comment

This doesn't answer the question, because you're iterating on the original HashMap, which isn't sorted.
5

you just need to use:

 Map<>.toString().replace("]","\n");

and replaces the ending square bracket of each key=value set with a new line.

Comments

3

Java 8

map.entrySet().stream().sorted(Map.Entry.comparingByValue()).forEach(System.out::println);

Comments

2
  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.

2 Comments

Beautiful. Had to delete my answer :)
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.
1

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 a lot 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<String, String> entry: listOfEntries)
   System.out.println(entry);

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

Comments

0

the simplest and shortest code i think is this:

public void listPrinter(LinkedHashMap<String, String> caseList) {

    for(Entry entry:caseList.entrySet()) {
        System.out.println("K: \t"+entry.getKey()+", V: \t"+entry.getValue());
    }
}

Comments

-1

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));
}

2 Comments

OP wants the output to be sorted by value, not by key.
Delete this - does not answer the question
-2

Try:

try
{
    int cnt= m.getSmartPhoneCount("HTC",true);      
    System.out.println("total count of HTC="+cnt);
}  
catch (NoSuchBrandSmartPhoneAvailableException e)
{
    // TODO Auto-generated catch 
    e.printStackTrace();
}

1 Comment

Was this intended to be posted as an answer to a different question? If so, please delete it here.
-3
 SmartPhone[] sp=new SmartPhone[4];
 sp[0]=new SmartPhone(1,"HTC","desire","black",20000,10,true,true);
 sp[1]=new SmartPhone(2,"samsung","grand","black",5000,10,false,true);
 sp[2]=new SmartPhone(14,"google nexus","desire","black",2000,30,true,false);
 sp[3]=new SmartPhone(13,"HTC","desire","white",50000,40,false,false);

2 Comments

Mind to explain your solution a bit? You might want to read How Do I Write A Good Answer.
Was this intended to be posted as an answer to a different question? If so, please delete it here.
-3
while (itr.hasNext()) {
    Vehicle vc=(Vehicle) itr.next();
    if(vc.getVehicleType().equalsIgnoreCase(s)) {
        count++;
    }
}

1 Comment

Was this intended to be posted as an answer to a different question? If so, please delete it here.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.